@budibase/server 1.0.48 → 1.0.49-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/builder/assets/{index.e083dcaf.js → index.21e57eb4.js} +234 -231
  2. package/builder/assets/index.83c0944f.css +1 -0
  3. package/builder/assets/{vendor.f9faf6ab.js → vendor.d526bfe8.js} +12 -12
  4. package/builder/index.html +3 -3
  5. package/coverage/clover.xml +2338 -2028
  6. package/coverage/coverage-final.json +100 -95
  7. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/application.js.html +210 -126
  10. package/coverage/lcov-report/api/controllers/auth.js.html +18 -6
  11. package/coverage/lcov-report/api/controllers/automation.js.html +21 -21
  12. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  15. package/coverage/lcov-report/api/controllers/datasource.js.html +72 -36
  16. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +53 -53
  18. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/layout.js.html +6 -6
  20. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/migrations.js.html +119 -0
  22. package/coverage/lcov-report/api/controllers/permission.js.html +15 -15
  23. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  24. package/coverage/lcov-report/api/controllers/query/index.js.html +19 -19
  25. package/coverage/lcov-report/api/controllers/query/validation.js.html +6 -6
  26. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  27. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/external.js.html +16 -16
  29. package/coverage/lcov-report/api/controllers/row/index.html +48 -33
  30. package/coverage/lcov-report/api/controllers/row/index.js.html +26 -26
  31. package/coverage/lcov-report/api/controllers/row/internal.js.html +95 -158
  32. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +41 -17
  33. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +551 -0
  34. package/coverage/lcov-report/api/controllers/row/utils.js.html +39 -57
  35. package/coverage/lcov-report/api/controllers/screen.js.html +7 -7
  36. package/coverage/lcov-report/api/controllers/script.js.html +4 -4
  37. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +629 -0
  38. package/coverage/lcov-report/api/controllers/table/external.js.html +12 -12
  39. package/coverage/lcov-report/api/controllers/table/index.html +46 -31
  40. package/coverage/lcov-report/api/controllers/table/index.js.html +53 -77
  41. package/coverage/lcov-report/api/controllers/table/internal.js.html +59 -35
  42. package/coverage/lcov-report/api/controllers/table/utils.js.html +217 -73
  43. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/user.js.html +30 -24
  45. package/coverage/lcov-report/api/controllers/view/exporters.js.html +4 -4
  46. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/index.js.html +14 -14
  48. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  49. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +7 -7
  50. package/coverage/lcov-report/api/controllers/webhook.js.html +15 -15
  51. package/coverage/lcov-report/api/index.html +1 -1
  52. package/coverage/lcov-report/api/index.js.html +8 -8
  53. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/index.html +18 -18
  65. package/coverage/lcov-report/api/routes/index.js.html +3 -3
  66. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/{hosting.js.html → migrations.js.html} +17 -14
  70. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/static.js.html +17 -2
  78. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  82. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  83. package/coverage/lcov-report/automations/actions.js.html +24 -24
  84. package/coverage/lcov-report/automations/automationUtils.js.html +5 -5
  85. package/coverage/lcov-report/automations/bullboard.js.html +16 -16
  86. package/coverage/lcov-report/automations/index.html +1 -1
  87. package/coverage/lcov-report/automations/index.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/bash.js.html +6 -6
  89. package/coverage/lcov-report/automations/steps/createRow.js.html +13 -19
  90. package/coverage/lcov-report/automations/steps/delay.js.html +4 -4
  91. package/coverage/lcov-report/automations/steps/deleteRow.js.html +11 -20
  92. package/coverage/lcov-report/automations/steps/discord.js.html +7 -7
  93. package/coverage/lcov-report/automations/steps/executeQuery.js.html +6 -6
  94. package/coverage/lcov-report/automations/steps/executeScript.js.html +6 -6
  95. package/coverage/lcov-report/automations/steps/filter.js.html +7 -7
  96. package/coverage/lcov-report/automations/steps/index.html +13 -13
  97. package/coverage/lcov-report/automations/steps/integromat.js.html +5 -5
  98. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +8 -8
  99. package/coverage/lcov-report/automations/steps/queryRows.js.html +10 -10
  100. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +5 -5
  101. package/coverage/lcov-report/automations/steps/serverLog.js.html +3 -3
  102. package/coverage/lcov-report/automations/steps/slack.js.html +5 -5
  103. package/coverage/lcov-report/automations/steps/updateRow.js.html +6 -6
  104. package/coverage/lcov-report/automations/steps/utils.js.html +3 -3
  105. package/coverage/lcov-report/automations/steps/zapier.js.html +5 -5
  106. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  107. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  108. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  110. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  111. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  112. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  113. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  114. package/coverage/lcov-report/automations/triggers.js.html +18 -18
  115. package/coverage/lcov-report/automations/utils.js.html +32 -32
  116. package/coverage/lcov-report/constants/index.html +5 -5
  117. package/coverage/lcov-report/constants/index.js.html +53 -26
  118. package/coverage/lcov-report/constants/layouts.js.html +5 -5
  119. package/coverage/lcov-report/constants/screens.js.html +4 -4
  120. package/coverage/lcov-report/db/client.js.html +18 -18
  121. package/coverage/lcov-report/db/inMemoryView.js.html +7 -7
  122. package/coverage/lcov-report/db/index.html +15 -15
  123. package/coverage/lcov-report/db/index.js.html +3 -3
  124. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +18 -18
  125. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  126. package/coverage/lcov-report/db/linkedRows/index.js.html +38 -41
  127. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +15 -15
  128. package/coverage/lcov-report/db/newid.js.html +4 -4
  129. package/coverage/lcov-report/db/utils.js.html +86 -86
  130. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  131. package/coverage/lcov-report/events/index.html +1 -1
  132. package/coverage/lcov-report/events/index.js.html +5 -5
  133. package/coverage/lcov-report/events/utils.js.html +3 -3
  134. package/coverage/lcov-report/index.html +114 -99
  135. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  136. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  137. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  138. package/coverage/lcov-report/middleware/authorized.js.html +166 -64
  139. package/coverage/lcov-report/middleware/builder.js.html +8 -8
  140. package/coverage/lcov-report/middleware/currentapp.js.html +29 -29
  141. package/coverage/lcov-report/middleware/index.html +30 -30
  142. package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
  143. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  144. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  145. package/coverage/lcov-report/middleware/usageQuota.js.html +270 -42
  146. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  147. package/coverage/lcov-report/threads/automation.js.html +1 -1
  148. package/coverage/lcov-report/threads/index.html +15 -15
  149. package/coverage/lcov-report/threads/index.js.html +10 -10
  150. package/coverage/lcov-report/threads/query.js.html +23 -8
  151. package/coverage/lcov-report/threads/utils.js.html +14 -14
  152. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  153. package/coverage/lcov-report/utilities/budibaseDir.js.html +7 -7
  154. package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
  155. package/coverage/lcov-report/utilities/csvParser.js.html +6 -6
  156. package/coverage/lcov-report/utilities/global.js.html +26 -26
  157. package/coverage/lcov-report/utilities/index.html +19 -19
  158. package/coverage/lcov-report/utilities/index.js.html +25 -25
  159. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +8 -8
  160. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  161. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  162. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  163. package/coverage/lcov-report/utilities/rowProcessor/index.html +27 -27
  164. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +115 -79
  165. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +75 -27
  166. package/coverage/lcov-report/utilities/scriptRunner.js.html +5 -5
  167. package/coverage/lcov-report/utilities/security.js.html +8 -8
  168. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  169. package/coverage/lcov-report/utilities/usageQuota/index.html +141 -0
  170. package/coverage/lcov-report/utilities/usageQuota/index.js.html +356 -0
  171. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +302 -0
  172. package/coverage/lcov-report/{api/controllers/hosting.js.html → utilities/usageQuota/usageQuoteReset.js.html} +36 -48
  173. package/coverage/lcov-report/utilities/users.js.html +5 -5
  174. package/coverage/lcov-report/utilities/workerRequests.js.html +39 -108
  175. package/coverage/lcov.info +3656 -3057
  176. package/dist/api/controllers/application.js +61 -34
  177. package/dist/api/controllers/auth.js +4 -0
  178. package/dist/api/controllers/datasource.js +11 -0
  179. package/dist/api/controllers/migrations.js +21 -0
  180. package/dist/api/controllers/row/internal.js +30 -53
  181. package/dist/api/controllers/row/internalSearch.js +12 -4
  182. package/dist/api/controllers/row/staticFormula.js +147 -0
  183. package/dist/api/controllers/row/utils.js +6 -8
  184. package/dist/api/controllers/static/index.js +59 -10
  185. package/dist/api/controllers/table/bulkFormula.js +160 -0
  186. package/dist/api/controllers/table/index.js +12 -9
  187. package/dist/api/controllers/table/internal.js +9 -0
  188. package/dist/api/controllers/table/utils.js +41 -12
  189. package/dist/api/controllers/user.js +2 -0
  190. package/dist/api/routes/index.js +2 -2
  191. package/dist/api/routes/migrations.js +9 -0
  192. package/dist/api/routes/static.js +2 -1
  193. package/dist/app.js +35 -5
  194. package/dist/automations/steps/createRow.js +2 -4
  195. package/dist/automations/steps/deleteRow.js +1 -4
  196. package/dist/constants/index.js +7 -0
  197. package/dist/db/linkedRows/index.js +4 -5
  198. package/dist/definitions/datasource.js +1 -0
  199. package/dist/environment.js +2 -0
  200. package/dist/integrations/base/sql.js +13 -6
  201. package/dist/integrations/googlesheets.js +340 -0
  202. package/dist/integrations/index.js +3 -0
  203. package/dist/integrations/utils.js +57 -9
  204. package/dist/middleware/authorized.js +55 -30
  205. package/dist/middleware/usageQuota.js +80 -13
  206. package/dist/migrations/functions/appUrls.js +46 -0
  207. package/dist/migrations/functions/quotas1.js +50 -0
  208. package/dist/migrations/functions/usageQuotas/index.js +20 -0
  209. package/dist/migrations/functions/usageQuotas/syncApps.js +32 -0
  210. package/dist/migrations/functions/usageQuotas/syncRows.js +35 -0
  211. package/dist/migrations/functions/userEmailViewCasing.js +24 -0
  212. package/dist/migrations/index.js +62 -0
  213. package/dist/package.json +8 -5
  214. package/dist/tests/utilities/TestConfiguration.js +13 -6
  215. package/dist/threads/query.js +4 -0
  216. package/dist/tsconfig.tsbuildinfo +1 -1
  217. package/dist/utilities/rowProcessor/index.js +18 -11
  218. package/dist/utilities/rowProcessor/utils.js +14 -4
  219. package/dist/utilities/{usageQuota.js → usageQuota/index.js} +44 -31
  220. package/dist/utilities/usageQuota/rows.js +77 -0
  221. package/dist/utilities/usageQuota/usageQuoteReset.js +16 -0
  222. package/dist/utilities/workerRequests.js +0 -20
  223. package/nodemon.json +1 -1
  224. package/package.json +9 -6
  225. package/src/api/controllers/application.js +52 -24
  226. package/src/api/controllers/auth.js +4 -0
  227. package/src/api/controllers/datasource.js +12 -0
  228. package/src/api/controllers/migrations.js +13 -0
  229. package/src/api/controllers/row/internal.js +29 -50
  230. package/src/api/controllers/row/internalSearch.js +12 -4
  231. package/src/api/controllers/row/staticFormula.js +157 -0
  232. package/src/api/controllers/row/utils.js +6 -12
  233. package/src/api/controllers/static/index.js +63 -10
  234. package/src/api/controllers/table/bulkFormula.js +183 -0
  235. package/src/api/controllers/table/index.js +16 -24
  236. package/src/api/controllers/table/internal.js +9 -1
  237. package/src/api/controllers/table/utils.js +57 -9
  238. package/src/api/controllers/user.js +2 -0
  239. package/src/api/routes/index.js +2 -2
  240. package/src/api/routes/migrations.js +14 -0
  241. package/src/api/routes/static.js +5 -0
  242. package/src/api/routes/tests/application.spec.js +2 -2
  243. package/src/api/routes/tests/auth.spec.js +1 -2
  244. package/src/api/routes/tests/static.spec.js +98 -0
  245. package/src/app.ts +18 -5
  246. package/src/automations/steps/createRow.js +2 -4
  247. package/src/automations/steps/deleteRow.js +1 -4
  248. package/src/constants/index.js +9 -0
  249. package/src/db/linkedRows/index.js +4 -5
  250. package/src/definitions/common.ts +3 -0
  251. package/src/definitions/datasource.ts +3 -0
  252. package/src/environment.js +2 -0
  253. package/src/integrations/base/sql.ts +14 -7
  254. package/src/integrations/googlesheets.ts +353 -0
  255. package/src/integrations/index.ts +3 -0
  256. package/src/integrations/tests/sql.spec.js +16 -0
  257. package/src/integrations/utils.ts +71 -11
  258. package/src/middleware/authorized.js +64 -30
  259. package/src/middleware/tests/authorized.spec.js +6 -4
  260. package/src/middleware/tests/usageQuota.spec.js +18 -24
  261. package/src/middleware/usageQuota.js +91 -15
  262. package/src/migrations/functions/appUrls.ts +34 -0
  263. package/src/migrations/functions/quotas1.ts +20 -0
  264. package/src/migrations/functions/tests/appUrls.spec.js +29 -0
  265. package/src/migrations/functions/tests/quotas1.spec.js +27 -0
  266. package/src/migrations/functions/tests/userEmailViewCasing.spec.js +25 -0
  267. package/src/migrations/functions/usageQuotas/index.ts +8 -0
  268. package/src/migrations/functions/usageQuotas/syncApps.ts +18 -0
  269. package/src/migrations/functions/usageQuotas/syncRows.ts +21 -0
  270. package/src/migrations/functions/usageQuotas/tests/syncApps.spec.js +37 -0
  271. package/src/migrations/functions/usageQuotas/tests/syncRows.spec.js +43 -0
  272. package/src/migrations/functions/userEmailViewCasing.ts +13 -0
  273. package/src/migrations/index.ts +56 -0
  274. package/src/tests/utilities/TestConfiguration.js +14 -6
  275. package/src/threads/query.js +5 -0
  276. package/src/utilities/rowProcessor/index.js +24 -12
  277. package/src/utilities/rowProcessor/utils.js +23 -7
  278. package/src/utilities/tests/usageQuota/usageQuota.spec.js +72 -0
  279. package/src/utilities/usageQuota/index.js +92 -0
  280. package/src/utilities/usageQuota/rows.js +74 -0
  281. package/src/utilities/usageQuota/usageQuoteReset.js +18 -0
  282. package/src/utilities/workerRequests.js +0 -23
  283. package/builder/assets/index.39e01193.css +0 -1
  284. package/dist/api/controllers/hosting.js +0 -30
  285. package/dist/api/routes/hosting.js +0 -11
  286. package/src/api/controllers/hosting.js +0 -22
  287. package/src/api/routes/hosting.js +0 -13
  288. package/src/api/routes/tests/hosting.spec.js +0 -36
  289. package/src/utilities/usageQuota.js +0 -73
@@ -61,7 +61,7 @@ function getLinksForRows(appId, rows) {
61
61
  .map(el => (Object.assign(Object.assign({}, el), { unique: el.id + el.thisId + el.fieldName }))), "unique");
62
62
  });
63
63
  }
64
- function getFullLinkedDocs(ctx, appId, links) {
64
+ function getFullLinkedDocs(appId, links) {
65
65
  return __awaiter(this, void 0, void 0, function* () {
66
66
  // create DBs
67
67
  const db = new CouchDB(appId);
@@ -132,13 +132,12 @@ exports.updateLinks = function (args) {
132
132
  /**
133
133
  * Given a table and a list of rows this will retrieve all of the attached docs and enrich them into the row.
134
134
  * This is required for formula fields, this may only be utilised internally (for now).
135
- * @param {object} ctx The request which is looking for rows.
135
+ * @param {string} appId The ID of the app which this request is in the context of.
136
136
  * @param {object} table The table from which the rows originated.
137
137
  * @param {array<object>} rows The rows which are to be enriched.
138
138
  * @return {Promise<*>} returns the rows with all of the enriched relationships on it.
139
139
  */
140
- exports.attachFullLinkedDocs = (ctx, table, rows) => __awaiter(void 0, void 0, void 0, function* () {
141
- const appId = ctx.appId;
140
+ exports.attachFullLinkedDocs = (appId, table, rows) => __awaiter(void 0, void 0, void 0, function* () {
142
141
  const linkedTableIds = getLinkedTableIDs(table);
143
142
  if (linkedTableIds.length === 0) {
144
143
  return rows;
@@ -150,7 +149,7 @@ exports.attachFullLinkedDocs = (ctx, table, rows) => __awaiter(void 0, void 0, v
150
149
  // clear any existing links that could be dupe'd
151
150
  rows = clearRelationshipFields(table, rows);
152
151
  // now get the docs and combine into the rows
153
- let linked = yield getFullLinkedDocs(ctx, appId, links);
152
+ let linked = yield getFullLinkedDocs(appId, links);
154
153
  const linkedTables = [];
155
154
  for (let row of rows) {
156
155
  for (let link of links.filter(link => link.thisId === row._id)) {
@@ -49,6 +49,7 @@ var SourceNames;
49
49
  SourceNames["ARANGODB"] = "ARANGODB";
50
50
  SourceNames["REST"] = "REST";
51
51
  SourceNames["ORACLE"] = "ORACLE";
52
+ SourceNames["GOOGLE_SHEETS"] = "GOOGLE_SHEETS";
52
53
  })(SourceNames = exports.SourceNames || (exports.SourceNames = {}));
53
54
  var IncludeRelationships;
54
55
  (function (IncludeRelationships) {
@@ -30,10 +30,12 @@ module.exports = {
30
30
  MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY,
31
31
  MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY,
32
32
  USE_QUOTAS: process.env.USE_QUOTAS,
33
+ EXCLUDE_QUOTAS_TENANTS: process.env.EXCLUDE_QUOTAS_TENANTS,
33
34
  REDIS_URL: process.env.REDIS_URL,
34
35
  REDIS_PASSWORD: process.env.REDIS_PASSWORD,
35
36
  INTERNAL_API_KEY: process.env.INTERNAL_API_KEY,
36
37
  MULTI_TENANCY: process.env.MULTI_TENANCY,
38
+ HTTP_MIGRATIONS: process.env.HTTP_MIGRATIONS,
37
39
  // environment
38
40
  NODE_ENV: process.env.NODE_ENV,
39
41
  JEST_WORKER_ID: process.env.JEST_WORKER_ID,
@@ -69,10 +69,16 @@ class InternalBuilder {
69
69
  this.client = client;
70
70
  }
71
71
  // right now we only do filters on the specific table being queried
72
- addFilters(tableName, query, filters) {
72
+ addFilters(query, filters, opts) {
73
73
  function iterate(structure, fn) {
74
74
  for (let [key, value] of Object.entries(structure)) {
75
- fn(`${tableName}.${key}`, value);
75
+ const isRelationshipField = key.includes(".");
76
+ if (!opts.relationship && !isRelationshipField) {
77
+ fn(`${opts.tableName}.${key}`, value);
78
+ }
79
+ if (opts.relationship && isRelationshipField) {
80
+ fn(key, value);
81
+ }
76
82
  }
77
83
  }
78
84
  if (!filters) {
@@ -248,7 +254,7 @@ class InternalBuilder {
248
254
  if (foundOffset) {
249
255
  query = query.offset(foundOffset);
250
256
  }
251
- query = this.addFilters(tableName, query, filters);
257
+ query = this.addFilters(query, filters, { tableName });
252
258
  // add sorting to pre-query
253
259
  query = this.addSorting(query, json);
254
260
  // @ts-ignore
@@ -261,13 +267,14 @@ class InternalBuilder {
261
267
  preQuery = this.addSorting(preQuery, json);
262
268
  }
263
269
  // handle joins
264
- return this.addRelationships(knex, preQuery, selectStatement, tableName, relationships);
270
+ query = this.addRelationships(knex, preQuery, selectStatement, tableName, relationships);
271
+ return this.addFilters(query, filters, { relationship: true });
265
272
  }
266
273
  update(knex, json, opts) {
267
274
  const { endpoint, body, filters } = json;
268
275
  let query = knex(endpoint.entityId);
269
276
  const parsedBody = parseBody(body);
270
- query = this.addFilters(endpoint.entityId, query, filters);
277
+ query = this.addFilters(query, filters, { tableName: endpoint.entityId });
271
278
  // mysql can't use returning
272
279
  if (opts.disableReturning) {
273
280
  return query.update(parsedBody);
@@ -279,7 +286,7 @@ class InternalBuilder {
279
286
  delete(knex, json, opts) {
280
287
  const { endpoint, filters } = json;
281
288
  let query = knex(endpoint.entityId);
282
- query = this.addFilters(endpoint.entityId, query, filters);
289
+ query = this.addFilters(query, filters, { tableName: endpoint.entityId });
283
290
  // mysql can't use returning
284
291
  if (opts.disableReturning) {
285
292
  return query.delete();
@@ -0,0 +1,340 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const datasource_1 = require("../definitions/datasource");
13
+ const google_auth_library_1 = require("google-auth-library");
14
+ const utils_1 = require("./utils");
15
+ const constants_1 = require("../constants");
16
+ const google_spreadsheet_1 = require("google-spreadsheet");
17
+ var GoogleSheetsModule;
18
+ (function (GoogleSheetsModule) {
19
+ const { getGlobalDB } = require("@budibase/backend-core/tenancy");
20
+ const { getScopedConfig } = require("@budibase/backend-core/db");
21
+ const { Configs } = require("@budibase/backend-core/constants");
22
+ const SCHEMA = {
23
+ plus: true,
24
+ auth: {
25
+ type: "google",
26
+ },
27
+ relationships: false,
28
+ docs: "https://developers.google.com/sheets/api/quickstart/nodejs",
29
+ description: "Create and collaborate on online spreadsheets in real-time and from any device. ",
30
+ friendlyName: "Google Sheets",
31
+ datasource: {
32
+ spreadsheetId: {
33
+ type: datasource_1.DatasourceFieldTypes.STRING,
34
+ required: true,
35
+ },
36
+ },
37
+ query: {
38
+ create: {
39
+ type: datasource_1.QueryTypes.FIELDS,
40
+ fields: {
41
+ sheet: {
42
+ type: datasource_1.DatasourceFieldTypes.STRING,
43
+ required: true,
44
+ },
45
+ row: {
46
+ type: datasource_1.QueryTypes.JSON,
47
+ required: true,
48
+ },
49
+ },
50
+ },
51
+ read: {
52
+ type: datasource_1.QueryTypes.FIELDS,
53
+ fields: {
54
+ sheet: {
55
+ type: datasource_1.DatasourceFieldTypes.STRING,
56
+ required: true,
57
+ },
58
+ },
59
+ },
60
+ update: {
61
+ type: datasource_1.QueryTypes.FIELDS,
62
+ fields: {
63
+ sheet: {
64
+ type: datasource_1.DatasourceFieldTypes.STRING,
65
+ required: true,
66
+ },
67
+ rowIndex: {
68
+ type: datasource_1.DatasourceFieldTypes.STRING,
69
+ required: true,
70
+ },
71
+ row: {
72
+ type: datasource_1.QueryTypes.JSON,
73
+ required: true,
74
+ },
75
+ },
76
+ },
77
+ delete: {
78
+ type: datasource_1.QueryTypes.FIELDS,
79
+ fields: {
80
+ sheet: {
81
+ type: datasource_1.DatasourceFieldTypes.STRING,
82
+ required: true,
83
+ },
84
+ rowIndex: {
85
+ type: datasource_1.DatasourceFieldTypes.NUMBER,
86
+ required: true,
87
+ },
88
+ },
89
+ },
90
+ },
91
+ };
92
+ class GoogleSheetsIntegration {
93
+ constructor(config) {
94
+ this.tables = {};
95
+ this.schemaErrors = {};
96
+ this.config = config;
97
+ const spreadsheetId = this.cleanSpreadsheetUrl(this.config.spreadsheetId);
98
+ this.client = new google_spreadsheet_1.GoogleSpreadsheet(spreadsheetId);
99
+ }
100
+ /**
101
+ * Pull the spreadsheet ID out from a valid google sheets URL
102
+ * @param spreadsheetId - the URL or standard spreadsheetId of the google sheet
103
+ * @returns spreadsheet Id of the google sheet
104
+ */
105
+ cleanSpreadsheetUrl(spreadsheetId) {
106
+ if (!spreadsheetId) {
107
+ throw new Error("You must set a spreadsheet ID in your configuration to fetch tables.");
108
+ }
109
+ const parts = spreadsheetId.split("/");
110
+ return parts.length > 5 ? parts[5] : spreadsheetId;
111
+ }
112
+ connect() {
113
+ return __awaiter(this, void 0, void 0, function* () {
114
+ try {
115
+ // Initialise oAuth client
116
+ const db = getGlobalDB();
117
+ const googleConfig = yield getScopedConfig(db, {
118
+ type: Configs.GOOGLE,
119
+ });
120
+ const oauthClient = new google_auth_library_1.OAuth2Client({
121
+ clientId: googleConfig.clientID,
122
+ clientSecret: googleConfig.clientSecret,
123
+ });
124
+ oauthClient.credentials.access_token = this.config.auth.accessToken;
125
+ oauthClient.credentials.refresh_token = this.config.auth.refreshToken;
126
+ this.client.useOAuth2Client(oauthClient);
127
+ yield this.client.loadInfo();
128
+ }
129
+ catch (err) {
130
+ console.error("Error connecting to google sheets", err);
131
+ throw err;
132
+ }
133
+ });
134
+ }
135
+ buildSchema(datasourceId) {
136
+ return __awaiter(this, void 0, void 0, function* () {
137
+ yield this.connect();
138
+ const sheets = yield this.client.sheetsByIndex;
139
+ const tables = {};
140
+ for (let sheet of sheets) {
141
+ // must fetch rows to determine schema
142
+ yield sheet.getRows();
143
+ // build schema
144
+ const schema = {};
145
+ // build schema from headers
146
+ for (let header of sheet.headerValues) {
147
+ schema[header] = {
148
+ name: header,
149
+ type: constants_1.FieldTypes.STRING,
150
+ };
151
+ }
152
+ // create tables
153
+ tables[sheet.title] = {
154
+ _id: utils_1.buildExternalTableId(datasourceId, sheet.title),
155
+ name: sheet.title,
156
+ primary: ["rowNumber"],
157
+ schema,
158
+ };
159
+ }
160
+ this.tables = tables;
161
+ });
162
+ }
163
+ query(json) {
164
+ return __awaiter(this, void 0, void 0, function* () {
165
+ const sheet = json.endpoint.entityId;
166
+ const handlers = {
167
+ [constants_1.DataSourceOperation.CREATE]: () => this.create({ sheet, row: json.body }),
168
+ [constants_1.DataSourceOperation.READ]: () => this.read({ sheet }),
169
+ [constants_1.DataSourceOperation.UPDATE]: () => {
170
+ var _a, _b, _c;
171
+ return this.update({
172
+ // exclude the header row and zero index
173
+ rowIndex: ((_c = (_b = (_a = json.extra) === null || _a === void 0 ? void 0 : _a.idFilter) === null || _b === void 0 ? void 0 : _b.equal) === null || _c === void 0 ? void 0 : _c.rowNumber) - 2,
174
+ sheet,
175
+ row: json.body,
176
+ });
177
+ },
178
+ [constants_1.DataSourceOperation.DELETE]: () => {
179
+ var _a, _b, _c;
180
+ return this.delete({
181
+ // exclude the header row and zero index
182
+ rowIndex: ((_c = (_b = (_a = json.extra) === null || _a === void 0 ? void 0 : _a.idFilter) === null || _b === void 0 ? void 0 : _b.equal) === null || _c === void 0 ? void 0 : _c.rowNumber) - 2,
183
+ sheet,
184
+ });
185
+ },
186
+ [constants_1.DataSourceOperation.CREATE_TABLE]: () => { var _a; return this.createTable((_a = json === null || json === void 0 ? void 0 : json.table) === null || _a === void 0 ? void 0 : _a.name); },
187
+ [constants_1.DataSourceOperation.UPDATE_TABLE]: () => this.updateTable(json.table),
188
+ [constants_1.DataSourceOperation.DELETE_TABLE]: () => { var _a; return this.deleteTable((_a = json === null || json === void 0 ? void 0 : json.table) === null || _a === void 0 ? void 0 : _a.name); },
189
+ };
190
+ const internalQueryMethod = handlers[json.endpoint.operation];
191
+ return yield internalQueryMethod();
192
+ });
193
+ }
194
+ buildRowObject(headers, values, rowNumber) {
195
+ const rowObject = { rowNumber };
196
+ for (let i = 0; i < headers.length; i++) {
197
+ rowObject._id = rowNumber;
198
+ rowObject[headers[i]] = values[i];
199
+ }
200
+ return rowObject;
201
+ }
202
+ createTable(name) {
203
+ return __awaiter(this, void 0, void 0, function* () {
204
+ try {
205
+ yield this.connect();
206
+ const sheet = yield this.client.addSheet({ title: name });
207
+ return sheet;
208
+ }
209
+ catch (err) {
210
+ console.error("Error creating new table in google sheets", err);
211
+ throw err;
212
+ }
213
+ });
214
+ }
215
+ updateTable(table) {
216
+ return __awaiter(this, void 0, void 0, function* () {
217
+ try {
218
+ yield this.connect();
219
+ const sheet = yield this.client.sheetsByTitle[table.name];
220
+ yield sheet.loadHeaderRow();
221
+ if (table._rename) {
222
+ const headers = [];
223
+ for (let header of sheet.headerValues) {
224
+ if (header === table._rename.old) {
225
+ headers.push(table._rename.updated);
226
+ }
227
+ else {
228
+ headers.push(header);
229
+ }
230
+ }
231
+ yield sheet.setHeaderRow(headers);
232
+ }
233
+ else {
234
+ let newField = Object.keys(table.schema).find(key => !sheet.headerValues.includes(key));
235
+ yield sheet.setHeaderRow([...sheet.headerValues, newField]);
236
+ }
237
+ }
238
+ catch (err) {
239
+ console.error("Error updating table in google sheets", err);
240
+ throw err;
241
+ }
242
+ });
243
+ }
244
+ deleteTable(sheet) {
245
+ return __awaiter(this, void 0, void 0, function* () {
246
+ try {
247
+ yield this.connect();
248
+ const sheetToDelete = yield this.client.sheetsByTitle[sheet];
249
+ return yield sheetToDelete.delete();
250
+ }
251
+ catch (err) {
252
+ console.error("Error deleting table in google sheets", err);
253
+ throw err;
254
+ }
255
+ });
256
+ }
257
+ create(query) {
258
+ return __awaiter(this, void 0, void 0, function* () {
259
+ try {
260
+ yield this.connect();
261
+ const sheet = yield this.client.sheetsByTitle[query.sheet];
262
+ const rowToInsert = typeof query.row === "string" ? JSON.parse(query.row) : query.row;
263
+ const row = yield sheet.addRow(rowToInsert);
264
+ return [
265
+ this.buildRowObject(sheet.headerValues, row._rawData, row._rowNumber),
266
+ ];
267
+ }
268
+ catch (err) {
269
+ console.error("Error writing to google sheets", err);
270
+ throw err;
271
+ }
272
+ });
273
+ }
274
+ read(query) {
275
+ return __awaiter(this, void 0, void 0, function* () {
276
+ try {
277
+ yield this.connect();
278
+ const sheet = yield this.client.sheetsByTitle[query.sheet];
279
+ const rows = yield sheet.getRows();
280
+ const headerValues = sheet.headerValues;
281
+ const response = [];
282
+ for (let row of rows) {
283
+ response.push(this.buildRowObject(headerValues, row._rawData, row._rowNumber));
284
+ }
285
+ return response;
286
+ }
287
+ catch (err) {
288
+ console.error("Error reading from google sheets", err);
289
+ throw err;
290
+ }
291
+ });
292
+ }
293
+ update(query) {
294
+ return __awaiter(this, void 0, void 0, function* () {
295
+ try {
296
+ yield this.connect();
297
+ const sheet = yield this.client.sheetsByTitle[query.sheet];
298
+ const rows = yield sheet.getRows();
299
+ const row = rows[query.rowIndex];
300
+ if (row) {
301
+ const updateValues = query.row;
302
+ for (let key in updateValues) {
303
+ row[key] = updateValues[key];
304
+ }
305
+ yield row.save();
306
+ return [
307
+ this.buildRowObject(sheet.headerValues, row._rawData, row._rowNumber),
308
+ ];
309
+ }
310
+ else {
311
+ throw new Error("Row does not exist.");
312
+ }
313
+ }
314
+ catch (err) {
315
+ console.error("Error reading from google sheets", err);
316
+ throw err;
317
+ }
318
+ });
319
+ }
320
+ delete(query) {
321
+ return __awaiter(this, void 0, void 0, function* () {
322
+ yield this.connect();
323
+ const sheet = yield this.client.sheetsByTitle[query.sheet];
324
+ const rows = yield sheet.getRows();
325
+ const row = rows[query.rowIndex];
326
+ if (row) {
327
+ yield row.delete();
328
+ return [{ deleted: query.rowIndex }];
329
+ }
330
+ else {
331
+ throw new Error("Row does not exist.");
332
+ }
333
+ });
334
+ }
335
+ }
336
+ module.exports = {
337
+ schema: SCHEMA,
338
+ integration: GoogleSheetsIntegration,
339
+ };
340
+ })(GoogleSheetsModule || (GoogleSheetsModule = {}));
@@ -10,6 +10,7 @@ const airtable = require("./airtable");
10
10
  const mysql = require("./mysql");
11
11
  const arangodb = require("./arangodb");
12
12
  const rest = require("./rest");
13
+ const googlesheets = require("./googlesheets");
13
14
  const { SourceNames } = require("../definitions/datasource");
14
15
  const DEFINITIONS = {
15
16
  [SourceNames.POSTGRES]: postgres.schema,
@@ -23,6 +24,7 @@ const DEFINITIONS = {
23
24
  [SourceNames.MYSQL]: mysql.schema,
24
25
  [SourceNames.ARANGODB]: arangodb.schema,
25
26
  [SourceNames.REST]: rest.schema,
27
+ [SourceNames.GOOGLE_SHEETS]: googlesheets.schema,
26
28
  };
27
29
  const INTEGRATIONS = {
28
30
  [SourceNames.POSTGRES]: postgres.integration,
@@ -36,6 +38,7 @@ const INTEGRATIONS = {
36
38
  [SourceNames.MYSQL]: mysql.integration,
37
39
  [SourceNames.ARANGODB]: arangodb.integration,
38
40
  [SourceNames.REST]: rest.integration,
41
+ [SourceNames.GOOGLE_SHEETS]: googlesheets.integration,
39
42
  };
40
43
  // optionally add oracle integration if the oracle binary can be installed
41
44
  if (!(process.arch === "arm64" && process.platform === "darwin")) {
@@ -125,7 +125,12 @@ function isSQL(datasource) {
125
125
  if (!datasource || !datasource.source) {
126
126
  return false;
127
127
  }
128
- const SQL = [datasource_1.SourceNames.POSTGRES, datasource_1.SourceNames.SQL_SERVER, datasource_1.SourceNames.MYSQL];
128
+ const SQL = [
129
+ datasource_1.SourceNames.POSTGRES,
130
+ datasource_1.SourceNames.SQL_SERVER,
131
+ datasource_1.SourceNames.MYSQL,
132
+ datasource_1.SourceNames.ORACLE,
133
+ ];
129
134
  return SQL.indexOf(datasource.source) !== -1;
130
135
  }
131
136
  exports.isSQL = isSQL;
@@ -137,8 +142,44 @@ function isIsoDateString(str) {
137
142
  return d.toISOString() === str;
138
143
  }
139
144
  exports.isIsoDateString = isIsoDateString;
140
- // add the existing relationships from the entities if they exist, to prevent them from being overridden
141
- function copyExistingPropsOver(tableName, table, entities) {
145
+ /**
146
+ * This function will determine whether a column is a relationship and whether it
147
+ * is currently valid. The reason for the validity check is that tables can be deleted
148
+ * outside of Budibase control and if this is the case it will break Budibase relationships.
149
+ * The tableIds is a list passed down from the main finalise tables function, which is
150
+ * based on the tables that have just been fetched. This will only really be used on subsequent
151
+ * fetches to the first one - if the user is periodically refreshing Budibase knowledge of tables.
152
+ * @param column The column to check, to see if it is a valid relationship.
153
+ * @param tableIds The IDs of the tables which currently exist.
154
+ */
155
+ function shouldCopyRelationship(column, tableIds) {
156
+ return (column.type === constants_1.FieldTypes.LINK &&
157
+ column.tableId &&
158
+ tableIds.includes(column.tableId));
159
+ }
160
+ /**
161
+ * Similar function to the shouldCopyRelationship function, but instead this looks for options and boolean
162
+ * types. It is possible to switch a string -> options and a number -> boolean (and vice versus) need to make
163
+ * sure that these get copied over when tables are fetched. Also checks whether they are still valid, if a
164
+ * column has changed type in the external database then copying it over may not be possible.
165
+ * @param column The column to check for options or boolean type.
166
+ * @param fetchedColumn The fetched column to check for the type in the external database.
167
+ */
168
+ function shouldCopySpecialColumn(column, fetchedColumn) {
169
+ return (column.type === constants_1.FieldTypes.OPTIONS ||
170
+ column.type === constants_1.FieldTypes.ARRAY ||
171
+ ((!fetchedColumn || fetchedColumn.type === constants_1.FieldTypes.NUMBER) &&
172
+ column.type === constants_1.FieldTypes.BOOLEAN));
173
+ }
174
+ /**
175
+ * Looks for columns which need to be copied over into the new table definitions, like relationships
176
+ * and options types.
177
+ * @param tableName The name of the table which is being checked.
178
+ * @param table The specific table which is being checked.
179
+ * @param entities All the tables that existed before - the old table definitions.
180
+ * @param tableIds The IDs of the tables which exist now, to check if anything has been removed.
181
+ */
182
+ function copyExistingPropsOver(tableName, table, entities, tableIds) {
142
183
  if (entities && entities[tableName]) {
143
184
  if (entities[tableName].primaryDisplay) {
144
185
  table.primaryDisplay = entities[tableName].primaryDisplay;
@@ -148,21 +189,28 @@ function copyExistingPropsOver(tableName, table, entities) {
148
189
  if (!existingTableSchema.hasOwnProperty(key)) {
149
190
  continue;
150
191
  }
151
- if (existingTableSchema[key].type === constants_1.FieldTypes.LINK ||
152
- existingTableSchema[key].type === constants_1.FieldTypes.OPTIONS ||
153
- existingTableSchema[key].type === constants_1.FieldTypes.ARRAY ||
154
- ((!table.schema[key] || table.schema[key].type === constants_1.FieldTypes.NUMBER) &&
155
- existingTableSchema[key].type === constants_1.FieldTypes.BOOLEAN)) {
192
+ const column = existingTableSchema[key];
193
+ if (shouldCopyRelationship(column, tableIds) ||
194
+ shouldCopySpecialColumn(column, table.schema[key])) {
156
195
  table.schema[key] = existingTableSchema[key];
157
196
  }
158
197
  }
159
198
  }
160
199
  return table;
161
200
  }
201
+ /**
202
+ * Look through the final table definitions to see if anything needs to be
203
+ * copied over from the old and if any errors have occurred mark them so
204
+ * that the user can be made aware.
205
+ * @param tables The list of tables that have been retrieved from the external database.
206
+ * @param entities The old list of tables, if there was any to look for definitions in.
207
+ */
162
208
  function finaliseExternalTables(tables, entities) {
163
209
  const invalidColumns = Object.values(constants_1.InvalidColumns);
164
210
  let finalTables = {};
165
211
  const errors = {};
212
+ // @ts-ignore
213
+ const tableIds = Object.values(tables).map(table => table._id);
166
214
  for (let [name, table] of Object.entries(tables)) {
167
215
  const schemaFields = Object.keys(table.schema);
168
216
  // make sure every table has a key
@@ -175,7 +223,7 @@ function finaliseExternalTables(tables, entities) {
175
223
  continue;
176
224
  }
177
225
  // make sure all previous props have been added back
178
- finalTables[name] = copyExistingPropsOver(name, table, entities);
226
+ finalTables[name] = copyExistingPropsOver(name, table, entities, tableIds);
179
227
  }
180
228
  // sort the tables by name
181
229
  finalTables = Object.entries(finalTables)