├── LICENSE ├── README.md └── code.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Kevin Nico - Academy Numérique 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoogleScriptSQL 2 | This library has been created to help people which have the desire using Google Sheet as a database for their App Script Project. This library **will only works** with Google Script. 3 | 4 | English docs : https://docs.yiono.fr/ 5 | 6 | Live demo : https://docs.yiono.fr/example-of-a-web-app-created-with-google-apps-script-and-yiono-library 7 | 8 | Link to the demos's source code : https://bit.ly/2ZkF5Mp 9 | 10 | Link to the demo's databse : https://bit.ly/3772xj2 11 | -------------------------------------------------------------------------------- /code.js: -------------------------------------------------------------------------------- 1 | var gSQL = function() { 2 | 3 | var Db, Table, Argument, Meth, Data, OriginalData, DataJoin, Row, Col, DataToUpdate,InnerData,AndIn, ColTake1, ColTake2; 4 | 5 | //Some functions 6 | function getData(db,tableName,argument){ 7 | var sheet = SpreadsheetApp.openById(db).getSheetByName(tableName); 8 | return sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues() 9 | } 10 | 11 | function insertion(db,table,data){ 12 | var id = checkIfIDIsExisting(db, table); 13 | var sheet = SpreadsheetApp.openById(db).getSheetByName(table); 14 | //if we insert only one row 15 | if (!Array.isArray(data[0])){ 16 | data.unshift(id + 1); 17 | sheet.appendRow(data); 18 | }else{ 19 | for (var i = 0, j = 1; i < data.length; i++, j++) { 20 | data[i].unshift(id + j); 21 | sheet.appendRow(data[i]); 22 | } 23 | } 24 | return "The data has been added to your table" 25 | } 26 | 27 | function aCompareToB(arg1, arg2, arg3, data, bool, Meth) { 28 | var position = data[0].indexOf(arg1); 29 | var map = data.map(function(r) {return r[position]}); 30 | var match = []; 31 | switch (arg2) { 32 | case '=': map.forEach(function(elt, index) {if(index > 0) {if(elt == arg3) {match.push(index);}}}); 33 | break; 34 | case '>': map.forEach(function(elt, index) {if(index > 0) {if (elt > arg3) {match.push(index);}}}); 35 | break; 36 | case '<': map.forEach(function(elt, index) {if(index > 0) {if (elt < arg3) {match.push(index);}}}); 37 | break; 38 | case '<=':map.forEach(function(elt, index) {if (index > 0) {if (elt <= arg3) {match.push(index);}}}); 39 | break; 40 | case '>=':map.forEach(function(elt, index) {if (index > 0) {if (elt >= arg3) {match.push(index);}}}); 41 | break; 42 | case '!=':map.forEach(function(elt, index) {if (index > 0) {if (elt != arg3) {match.push(index);}}}); 43 | break; 44 | } 45 | if (bool == true) { 46 | var returnData = []; 47 | }else { 48 | var returnData = [data[0]]; 49 | } 50 | match.forEach(function(elt) { 51 | returnData.push(data[elt]); 52 | 53 | }); 54 | 55 | 56 | if (Meth == "GET") { 57 | return returnData 58 | }else if (Meth == "UPDATE") { 59 | return [match, returnData] 60 | } 61 | } 62 | 63 | function compareArray(a, b) { 64 | var array = []; 65 | var map = b.map(function(r) {return r[0]}); 66 | a.forEach(function(elt) { 67 | var pos = map.indexOf(elt[0]) 68 | if (pos > -1) { 69 | array.push(pos); 70 | } 71 | }); 72 | return array 73 | } 74 | function checkIfIDIsExisting(db, table) { 75 | var value = SpreadsheetApp.openById(db).getSheetByName(table).getRange(2, 1).getValue() 76 | if (value === "") { 77 | return -1 78 | } else { 79 | return SpreadsheetApp.openById(db).getSheetByName(table).getRange(SpreadsheetApp.openById(db).getSheetByName(table).getLastRow(), 1).getValue() 80 | } 81 | } 82 | 83 | 84 | 85 | 86 | 87 | 88 | this.CREATEDB = function(dbName){ 89 | Db = SpreadsheetApp.create(dbName).getId(); 90 | return this 91 | } 92 | 93 | this.INFOLDER = function(folderId){ 94 | 95 | var file = DriveApp.getFileById(Db); 96 | var folder = DriveApp.getFolderById(folderId); 97 | var newFile = file.makeCopy(folder).setName(file.getName()); 98 | Db = newFile.getId(); 99 | file.setTrashed(true); 100 | return this 101 | } 102 | 103 | this.SETTABLES = function(tablesNames){ 104 | var spreadSheet = SpreadsheetApp.openById(Db); 105 | if(typeof tablesNames != "string"){ 106 | tablesNames.forEach(function(elt){ 107 | spreadSheet.insertSheet(elt); 108 | }); 109 | }else { 110 | spreadSheet.insertSheet(tablesNames) 111 | } 112 | Table = tablesNames; 113 | return this 114 | } 115 | 116 | this.SETCOLUMNS = function(tableColumns){ 117 | 118 | var spreadSheet = SpreadsheetApp.openById(Db); 119 | if(typeof Table == "string"){ 120 | tableColumns.unshift("ID"); 121 | spreadSheet.getSheetByName(Table).appendRow(tableColumns); 122 | SpreadsheetApp.openById(Db).deleteSheet(SpreadsheetApp.openById(Db).getSheets()[0]); 123 | }else{ 124 | for(var i = 0; i< tableColumns.length; i++){ 125 | tableColumns[i].unshift("ID"); 126 | spreadSheet.getSheetByName(Table[i]).appendRow(tableColumns[i]); 127 | } 128 | SpreadsheetApp.openById(Db).deleteSheet(SpreadsheetApp.openById(Db).getSheets()[0]); 129 | } 130 | return "Database, Table and Columns have been created with success" 131 | } 132 | 133 | this.INSERTCOL = function(colName){ 134 | var sheet = SpreadsheetApp.openById(Db).getSheetByName(Table); 135 | if(typeof colName == "string"){ 136 | sheet.getRange(1,sheet.getLastColumn()+1).setValue(colName); 137 | }else{ 138 | colName.forEach(function(elt){ 139 | sheet.getRange(1,sheet.getLastColumn()+1).setValue(elt); 140 | }); 141 | } 142 | return "The column has been added" 143 | } 144 | 145 | this.DB = function(dbId) { 146 | Db = dbId; 147 | return this 148 | } 149 | 150 | //------------------------------------------ 151 | this.TABLE = function(tableName) { 152 | Table = tableName; 153 | return this 154 | } 155 | 156 | //---------------------------------------------------------------------------------------------------------- 157 | this.INSERT = function(data) { 158 | 159 | return insertion(Db,Table,data) 160 | } 161 | 162 | //------------------------------------------------------------------------------------------------------------- 163 | this.SELECT = function(argument) { 164 | 165 | Argument = argument; 166 | if(Meth == undefined){ 167 | Meth = "GET" 168 | } 169 | var sheet = SpreadsheetApp.openById(Db).getSheetByName(Table); 170 | Data = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues() 171 | 172 | 173 | if(Meth == "GET"){ 174 | OriginalData = Data; 175 | }else if (Meth == "JOIN"){ 176 | DataJoin = Data; 177 | } 178 | 179 | return this 180 | } 181 | 182 | 183 | 184 | //----------------------------------------------------------------------------------------------------------- 185 | this.UPDATE = function(a) { 186 | 187 | Meth = "UPDATE"; 188 | var sheet = SpreadsheetApp.openById(Db).getSheetByName(Table); 189 | Data = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues(); 190 | OriginalData= Data; 191 | var headers = Data[0] 192 | var position = [] 193 | if (typeof a == "string") { 194 | var b = headers.indexOf(a); 195 | position.push(b); 196 | } else { 197 | a.forEach(function(elt) { 198 | var b = headers.indexOf(elt); 199 | position.push(b); 200 | }); 201 | } 202 | Col = position; 203 | return this 204 | } 205 | 206 | //------------------------------------------------------------------------------------------------------------ 207 | 208 | //------------------------------------------------------------------------------------------------------------ 209 | this.VALUES = function(values) { 210 | DataToUpdate = values; 211 | return this 212 | } 213 | //----------------------------------------------------------------------------------------------------------- 214 | 215 | this.DELETEWHERE = function(a, b, c) { 216 | var call1 = this.SELECT("ALL"); 217 | var call2 = this.WHERE(a, b, c); 218 | var m = OriginalData.map(function(r) {return r[0]}); 219 | var map = m.splice(1, (m.length - 1)) 220 | var sheet = SpreadsheetApp.openById(Db).getSheetByName(Table); 221 | var length = Data.length; 222 | Data.reverse().forEach(function(elt, index) { 223 | if (index < length) { 224 | var pos = map.indexOf(elt[0]); 225 | if (pos > -1) { 226 | sheet.deleteRow(pos + 2); 227 | } 228 | } 229 | }); 230 | return "The values have been deleted" 231 | } 232 | //-------------------------------------------------------------------------------------------------------------- 233 | this.TRUNCATE = function() { 234 | 235 | var sheet = SpreadsheetApp.openById(Db).getSheetByName(Table); 236 | 237 | sheet.deleteRows(2, sheet.getLastRow() - 1); 238 | 239 | return "The table " + Table + " has been emptied"; 240 | 241 | 242 | } 243 | 244 | //---------------------------------------------------------------------------------------------------------------- 245 | this.DROPDB = function() { 246 | 247 | DriveApp.getFileById(Db).setTrashed(true); 248 | 249 | return "The Database have been deleted, if it was an error, you can find it in your drive --> Trash" 250 | } 251 | //-------------------------------------------------------------------------------------------------------------- 252 | this.DROPTABLE = function() { 253 | 254 | var db = SpreadsheetApp.openById(Db); 255 | var sheet = db.getSheetByName(Table); 256 | db.deleteSheet(sheet); 257 | 258 | return "The table have been deleted" 259 | } 260 | 261 | //----------------------------------------------------------------------------------------------------------- 262 | this.WHERE = function(a, b, c) { 263 | 264 | var data = aCompareToB(a, b, c, Data, false, Meth); 265 | if (Meth == "GET") { 266 | Data = data; 267 | 268 | } else if (Meth == "UPDATE") { 269 | Data = data[1]; 270 | Row = data[0]; 271 | 272 | } 273 | return this 274 | } 275 | //----------------------------------------------------------------------------------------------------------- 276 | 277 | this.AND = function(a, b, c) { 278 | var data = aCompareToB(a, b, c, Data, false, Meth); 279 | if (Meth == "GET") { 280 | Data = data; 281 | 282 | }else if (Meth == "UPDATE") { 283 | Data = data[1]; 284 | var rowArray = compareArray(data[1],OriginalData); 285 | Row = rowArray.splice(1, (rowArray.length - 1)) 286 | 287 | 288 | } 289 | return this 290 | } 291 | //----------------------------------------------------------------------------------------------------------- 292 | this.OR = function(a, b, c) { 293 | var data = aCompareToB(a, b, c, OriginalData, true, Meth); 294 | if (Meth == "UPDATE") { 295 | data = data[1] 296 | }; 297 | var dataToCompare = Data; 298 | var array = [OriginalData[0]]; 299 | for (var i = 1; i < dataToCompare.length; i++) { 300 | var j = []; 301 | var eltToCompare = Number(dataToCompare[i][0]); 302 | data.forEach(function(elt) { 303 | if (Number(elt[0]) == eltToCompare) { 304 | j.push('1'); 305 | } 306 | }); 307 | if (j.length == 0) { 308 | array.push(dataToCompare[i]) 309 | } 310 | } 311 | var concatArray = array.concat(data); 312 | var arraySorted = concatArray.sort(function(a, b) {return a[0] - b[0]}); 313 | Data = arraySorted; 314 | if (Meth == "UPDATE") { 315 | var rowArray = compareArray(arraySorted, OriginalData); 316 | Row = rowArray.splice(1, (rowArray.length - 1)); 317 | } 318 | return this 319 | 320 | 321 | } 322 | //---------------------------------------------------------------------------------------------------------------- 323 | this.INNERJOIN = function(a) { 324 | Meth = "INNERJOIN"; 325 | var sheet = SpreadsheetApp.openById(Db).getSheetByName(a); 326 | InnerData = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues(); 327 | return this 328 | } 329 | //--------------------------------------------------------------------------------------------------------------- 330 | 331 | 332 | 333 | this.TAKE = function(col){ 334 | this.SELECT(col);//Call to get the Whole values 335 | var data1 = Data 336 | var DataToKeep = [data1] 337 | var data2 = this.getVal(); 338 | var DataToKeep = [data1, data2]; 339 | if(AndIn == undefined){ 340 | ColTake1 = DataToKeep; 341 | }else{ 342 | ColTake2 = DataToKeep; 343 | } 344 | return this 345 | } 346 | 347 | //------------------------------------------------------------------------------------------------------------------------- 348 | this.ANDIN = function(tableName){ 349 | AndIn = true; 350 | Table = tableName 351 | return this 352 | } 353 | 354 | //---------------------------------------------------------------------------------------------------------------------------------- 355 | this.JOINWHERE = function(a,b,c){ 356 | 357 | function joinReturnValue(m,n){ 358 | if(!Array.isArray(m) && !Array.isArray(n)){ 359 | return [m,n] 360 | }else if (Array.isArray(m) && !Array.isArray(n)){ 361 | return m.concat(n) 362 | }else if (!Array.isArray(m) && Array.isArray(n)){ 363 | n.unshift(m); 364 | return n 365 | }else { 366 | //Logger.log(m.concat(n)); 367 | //Logger.log(n); 368 | return m.concat(n) 369 | } 370 | 371 | } 372 | var argument = b; 373 | var header1 = ColTake1[0][0]; 374 | var header2 = ColTake2[0][0]; 375 | var position1 = header1.indexOf(a);; 376 | var position2 = header2.indexOf(c); 377 | var d = ColTake1[1]; 378 | var e = ColTake2[1]; 379 | var f = ColTake1[0].map(function(r){ return r[position1]}); 380 | var g = ColTake2[0].map(function(r){ return r[position2]}); 381 | var returnValues = [] 382 | 383 | switch (argument) { 384 | case '=': for(var i = 1; i< f.length; i++){ for(var j = 1; j< g.length; j++){if(f[i] == g[j]){returnValues.push(joinReturnValue(d[i-1],e[j-1]));}}} 385 | break; 386 | case '>':for(var i = 1; i< f.length; i++){for(var j = 1; j< g.length; j++){if(f[i] > g[j]){returnValues.push(joinReturnValue(d[i-1],e[j-1]));}}} 387 | break; 388 | case '<': for(var i = 1; i< f.length; i++){for(var j = 1; j< g.length; j++){if(f[i] < g[j]){returnValues.push(joinReturnValue(d[i-1],e[j-1]));}}} 389 | break; 390 | case '<=':for(var i = 1; i< f.length; i++){for(var j = 1; j< g.length; j++){if(f[i] <= g[j]){returnValues.push(joinReturnValue(d[i-1],e[j-1]));}}} 391 | break; 392 | case '>=':for(var i = 1; i< f.length; i++){for(var j = 1; j< g.length; j++){if(f[i] >= g[j]){returnValues.push(joinReturnValue(d[i-1],e[j-1]));}}} 393 | break; 394 | case '!=':for(var i = 1; i< f.length; i++){for(var j = 1; j< g.length; j++){if(f[i] != g[j]){returnValues.push(joinReturnValue(d[i-1],e[j-1]));}}} 395 | break; 396 | } 397 | 398 | return returnValues 399 | } 400 | 401 | //---------------------------------------------------------------------------------------------------------------- 402 | this.getVal = function() { 403 | if(Argument == "ALL"){ 404 | return Data.splice(1,(Data.length - 1)) 405 | }else if (typeof Argument == "string" && Argument != "ALL"){ 406 | var headers = Data[0]; 407 | var position = headers.indexOf(Argument); 408 | var dataToReturn = Data.map(function(r){return r[position]}); 409 | return dataToReturn.splice(1,(dataToReturn.length - 1)); 410 | }else if (Array.isArray(Argument)){ 411 | var headers = Data[0]; 412 | var array = []; 413 | Argument.forEach(function(elt) { 414 | var position = headers.indexOf(elt); 415 | array.push(Data.map(function(r) {return r[position]})); 416 | }); 417 | var newArray = []; 418 | for (var i = 0; i < array[0].length; i++ ){ 419 | var arr = []; 420 | for(var j = 0; j< array.length; j++){ 421 | arr.push(array[j][i]); 422 | } 423 | newArray.push(arr); 424 | } 425 | return newArray.splice(1,(newArray.length -1)) 426 | } 427 | 428 | 429 | 430 | } 431 | 432 | //------------------------------------------------------------------------------------------------------------------------------------------- 433 | this.setVal = function() { 434 | var dataToUpdate = DataToUpdate; 435 | var sheet = SpreadsheetApp.openById(Db).getSheetByName(Table); 436 | 437 | if (Row == undefined && Col.length == 1) { 438 | var dataToInsert = []; 439 | for (var i = 0; i < (sheet.getLastRow() - 1); i++) { 440 | var data = [dataToUpdate]; 441 | dataToInsert.push(data); 442 | //sheet.getRange(i+2, (Col[0] + 1)).setValue(dataToUpdate); 443 | } 444 | sheet.getRange(2, (Col[0] + 1), (sheet.getLastRow() - 1)).setValues(dataToInsert); 445 | return "The values have been updated" 446 | } else if (Row == undefined && Col.length > 1) { 447 | for (var i = 0; i < Col.length; i++) { 448 | var dataToInsert = []; 449 | for (var j = 0; j < (sheet.getLastRow() - 1); j++) { 450 | var data = [dataToUpdate[i]]; 451 | dataToInsert.push(data); 452 | } 453 | sheet.getRange(2, (Col[i] + 1), (sheet.getLastRow() - 1)).setValues(dataToInsert); 454 | } 455 | return "The values have been updated" 456 | } else if (Row != undefined) { 457 | if(Row.length >0 && Row.length < 2 && Col.length < 2){ 458 | sheet.getRange(Number(Row)+1, Number(Col)+1).setValue(DataToUpdate); 459 | 460 | }else if(Row.length > 1 && Col.length <2){ 461 | Row.forEach(function(elt){ 462 | sheet.getRange(elt+1, Number(Col)+1).setValue(DataToUpdate); 463 | }); 464 | 465 | }else if(Row.length < 2 && Row.length >0 && Col.length > 1){ 466 | Col.forEach(function(elt,index){ 467 | sheet.getRange(Number(Row)+1, elt+1).setValue(DataToUpdate[index]); 468 | 469 | }) 470 | }else if(Row.length >0){ 471 | 472 | for (var i = 0; i < Col.length; i++) { 473 | var col = Col[i]; 474 | var value = dataToUpdate[i]; 475 | Row.forEach(function(elt) { 476 | 477 | sheet.getRange(elt + 1, col + 1).setValue(value); 478 | }); 479 | } 480 | } 481 | return "The values have been updated" 482 | } 483 | } 484 | } 485 | 486 | --------------------------------------------------------------------------------