@budibase/server 0.9.186 → 0.9.190-alpha.0

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 (309) hide show
  1. package/Dockerfile +7 -1
  2. package/LICENSE +1 -1
  3. package/__mocks__/mssql.ts +1 -1
  4. package/__mocks__/oracledb.ts +31 -0
  5. package/__mocks__/pg.ts +3 -0
  6. package/builder/assets/bb-space-man.5be51a45.svg +290 -0
  7. package/builder/assets/index.43f4c913.js +1316 -0
  8. package/builder/assets/index.7d405e74.css +1 -0
  9. package/builder/assets/oracle.66592424.png +0 -0
  10. package/builder/assets/vendor.470042a4.js +152 -0
  11. package/builder/assets/vendor.5e1fe644.css +1 -0
  12. package/builder/index.html +4 -4
  13. package/coverage/clover.xml +1520 -1087
  14. package/coverage/coverage-final.json +93 -89
  15. package/coverage/lcov-report/api/controllers/analytics.js.html +2 -2
  16. package/coverage/lcov-report/api/controllers/apikeys.js.html +2 -2
  17. package/coverage/lcov-report/api/controllers/application.js.html +64 -13
  18. package/coverage/lcov-report/api/controllers/auth.js.html +19 -10
  19. package/coverage/lcov-report/api/controllers/automation.js.html +3 -3
  20. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  23. package/coverage/lcov-report/api/controllers/datasource.js.html +232 -28
  24. package/coverage/lcov-report/api/controllers/dev.js.html +16 -7
  25. package/coverage/lcov-report/api/controllers/hosting.js.html +10 -10
  26. package/coverage/lcov-report/api/controllers/index.html +91 -91
  27. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/layout.js.html +3 -3
  29. package/coverage/lcov-report/api/controllers/metadata.js.html +3 -3
  30. package/coverage/lcov-report/api/controllers/permission.js.html +3 -3
  31. package/coverage/lcov-report/api/controllers/query.js.html +53 -209
  32. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  33. package/coverage/lcov-report/api/controllers/routing.js.html +3 -3
  34. package/coverage/lcov-report/api/controllers/row/external.js.html +17 -8
  35. package/coverage/lcov-report/api/controllers/row/index.html +26 -26
  36. package/coverage/lcov-report/api/controllers/row/index.js.html +2 -2
  37. package/coverage/lcov-report/api/controllers/row/internal.js.html +9 -9
  38. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +2 -2
  39. package/coverage/lcov-report/api/controllers/row/utils.js.html +21 -30
  40. package/coverage/lcov-report/api/controllers/screen.js.html +2 -2
  41. package/coverage/lcov-report/api/controllers/script.js.html +3 -3
  42. package/coverage/lcov-report/api/controllers/table/external.js.html +1001 -0
  43. package/coverage/lcov-report/api/controllers/table/index.html +56 -26
  44. package/coverage/lcov-report/api/controllers/table/index.js.html +80 -350
  45. package/coverage/lcov-report/api/controllers/table/internal.js.html +545 -0
  46. package/coverage/lcov-report/api/controllers/table/utils.js.html +175 -52
  47. package/coverage/lcov-report/api/controllers/templates.js.html +4 -4
  48. package/coverage/lcov-report/api/controllers/user.js.html +390 -33
  49. package/coverage/lcov-report/api/controllers/view/exporters.js.html +19 -4
  50. package/coverage/lcov-report/api/controllers/view/index.html +22 -22
  51. package/coverage/lcov-report/api/controllers/view/index.js.html +52 -13
  52. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  53. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +3 -3
  54. package/coverage/lcov-report/api/controllers/webhook.js.html +4 -4
  55. package/coverage/lcov-report/api/index.html +1 -1
  56. package/coverage/lcov-report/api/index.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/dev.js.html +2 -2
  68. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/index.html +4 -4
  70. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/query.js.html +5 -2
  76. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/static.js.html +2 -2
  82. package/coverage/lcov-report/api/routes/table.js.html +35 -2
  83. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  84. package/coverage/lcov-report/api/routes/user.js.html +17 -2
  85. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  86. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  87. package/coverage/lcov-report/automations/actions.js.html +2 -2
  88. package/coverage/lcov-report/automations/automationUtils.js.html +4 -4
  89. package/coverage/lcov-report/automations/bullboard.js.html +71 -20
  90. package/coverage/lcov-report/automations/index.html +35 -50
  91. package/coverage/lcov-report/automations/index.js.html +2 -2
  92. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/discord.js.html +3 -3
  97. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/executeScript.js.html +3 -3
  99. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/index.html +14 -14
  101. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +3 -3
  103. package/coverage/lcov-report/automations/steps/queryRows.js.html +3 -3
  104. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  106. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  107. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  108. package/coverage/lcov-report/automations/steps/utils.js.html +7 -7
  109. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  111. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  112. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  113. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  114. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  115. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  116. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  117. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  118. package/coverage/lcov-report/automations/triggers.js.html +22 -10
  119. package/coverage/lcov-report/automations/utils.js.html +42 -12
  120. package/coverage/lcov-report/constants/index.html +5 -5
  121. package/coverage/lcov-report/constants/index.js.html +87 -21
  122. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  123. package/coverage/lcov-report/constants/screens.js.html +1 -1
  124. package/coverage/lcov-report/db/client.js.html +2 -2
  125. package/coverage/lcov-report/db/inMemoryView.js.html +2 -2
  126. package/coverage/lcov-report/db/index.html +2 -2
  127. package/coverage/lcov-report/db/index.js.html +1 -1
  128. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +6 -6
  129. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  130. package/coverage/lcov-report/db/linkedRows/index.js.html +5 -5
  131. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +6 -6
  132. package/coverage/lcov-report/db/newid.js.html +3 -3
  133. package/coverage/lcov-report/db/utils.js.html +57 -57
  134. package/coverage/lcov-report/events/AutomationEmitter.js.html +6 -6
  135. package/coverage/lcov-report/events/index.html +6 -6
  136. package/coverage/lcov-report/events/index.js.html +1 -1
  137. package/coverage/lcov-report/events/utils.js.html +5 -5
  138. package/coverage/lcov-report/index.html +108 -93
  139. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  140. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  141. package/coverage/lcov-report/middleware/appInfo.js.html +2 -2
  142. package/coverage/lcov-report/middleware/authorized.js.html +58 -34
  143. package/coverage/lcov-report/middleware/builder.js.html +16 -7
  144. package/coverage/lcov-report/middleware/currentapp.js.html +6 -6
  145. package/coverage/lcov-report/middleware/index.html +27 -27
  146. package/coverage/lcov-report/middleware/joi-validator.js.html +2 -2
  147. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  148. package/coverage/lcov-report/middleware/selfhost.js.html +2 -2
  149. package/coverage/lcov-report/middleware/usageQuota.js.html +4 -4
  150. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  151. package/coverage/lcov-report/{automations/thread.js.html → threads/automation.js.html} +90 -33
  152. package/coverage/lcov-report/threads/index.html +141 -0
  153. package/coverage/lcov-report/threads/index.js.html +278 -0
  154. package/coverage/lcov-report/threads/query.js.html +278 -0
  155. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  156. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  157. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  158. package/coverage/lcov-report/utilities/csvParser.js.html +144 -15
  159. package/coverage/lcov-report/utilities/global.js.html +26 -11
  160. package/coverage/lcov-report/utilities/index.html +48 -48
  161. package/coverage/lcov-report/utilities/index.js.html +47 -14
  162. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +30 -9
  163. package/coverage/lcov-report/utilities/queue/index.html +14 -14
  164. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  165. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  166. package/coverage/lcov-report/utilities/rowProcessor/index.html +4 -4
  167. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +2 -2
  168. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +3 -3
  169. package/coverage/lcov-report/utilities/scriptRunner.js.html +16 -7
  170. package/coverage/lcov-report/utilities/security.js.html +3 -3
  171. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  172. package/coverage/lcov-report/utilities/users.js.html +1 -1
  173. package/coverage/lcov-report/utilities/workerRequests.js.html +5 -5
  174. package/coverage/lcov.info +2558 -1787
  175. package/dist/api/controllers/application.js +15 -1
  176. package/dist/api/controllers/auth.js +3 -3
  177. package/dist/api/controllers/datasource.js +67 -16
  178. package/dist/api/controllers/deploy/index.js +2 -0
  179. package/dist/api/controllers/dev.js +4 -1
  180. package/dist/api/controllers/query.js +30 -58
  181. package/dist/api/controllers/row/ExternalRequest.js +37 -14
  182. package/dist/api/controllers/row/external.js +3 -1
  183. package/dist/api/controllers/row/utils.js +6 -12
  184. package/dist/api/controllers/table/external.js +249 -0
  185. package/dist/api/controllers/table/index.js +49 -123
  186. package/dist/api/controllers/table/internal.js +150 -0
  187. package/dist/api/controllers/table/utils.js +62 -28
  188. package/dist/api/controllers/user.js +123 -11
  189. package/dist/api/controllers/view/exporters.js +4 -0
  190. package/dist/api/controllers/view/index.js +14 -2
  191. package/dist/api/routes/query.js +1 -1
  192. package/dist/api/routes/table.js +7 -1
  193. package/dist/api/routes/user.js +2 -1
  194. package/dist/app.js +2 -11
  195. package/dist/automations/bullboard.js +37 -10
  196. package/dist/automations/triggers.js +7 -3
  197. package/dist/automations/utils.js +11 -2
  198. package/dist/constants/index.js +19 -0
  199. package/dist/definitions/datasource.js +5 -0
  200. package/dist/environment.js +13 -0
  201. package/dist/integrations/base/IntegrationBase.js +2 -0
  202. package/dist/integrations/base/datasourcePlus.js +2 -0
  203. package/dist/integrations/base/sql.js +338 -180
  204. package/dist/integrations/base/sqlTable.js +143 -0
  205. package/dist/integrations/base/utils.js +30 -0
  206. package/dist/integrations/index.js +6 -0
  207. package/dist/integrations/microsoftSqlServer.js +117 -9
  208. package/dist/integrations/mysql.js +14 -84
  209. package/dist/integrations/oracle.js +345 -0
  210. package/dist/integrations/postgres.js +35 -28
  211. package/dist/integrations/utils.js +71 -9
  212. package/dist/middleware/authorized.js +22 -11
  213. package/dist/middleware/builder.js +4 -1
  214. package/dist/package.json +13 -8
  215. package/dist/tests/utilities/TestConfiguration.js +2 -1
  216. package/dist/{automations/thread.js → threads/automation.js} +26 -8
  217. package/dist/threads/index.js +64 -0
  218. package/dist/threads/query.js +64 -0
  219. package/dist/tsconfig.tsbuildinfo +1 -1
  220. package/dist/utilities/csvParser.js +46 -5
  221. package/dist/utilities/global.js +6 -2
  222. package/dist/utilities/index.js +11 -0
  223. package/dist/utilities/queue/inMemoryQueue.js +8 -0
  224. package/dist/utilities/scriptRunner.js +4 -1
  225. package/package.json +14 -9
  226. package/scripts/dev/manage.js +1 -0
  227. package/scripts/integrations/mssql/data/Dockerfile +9 -0
  228. package/scripts/integrations/mssql/data/entrypoint.sh +24 -0
  229. package/scripts/integrations/mssql/data/setup.sql +54 -0
  230. package/scripts/integrations/mssql/docker-compose.yaml +12 -0
  231. package/scripts/integrations/mssql/reset.sh +3 -0
  232. package/scripts/integrations/oracle/docker-compose.yml +19 -0
  233. package/scripts/integrations/oracle/instantclient/linux/x86-64/basiclite-21.4.zip +0 -0
  234. package/scripts/integrations/oracle/instantclient/linux/x86-64/install.sh +23 -0
  235. package/scripts/integrations/oracle/oracle.md +90 -0
  236. package/scripts/integrations/postgres/docker-compose.yml +3 -3
  237. package/scripts/likeCypress.ts +33 -0
  238. package/src/api/controllers/application.js +18 -1
  239. package/src/api/controllers/auth.js +3 -0
  240. package/src/api/controllers/datasource.js +84 -16
  241. package/src/api/controllers/deploy/index.js +2 -0
  242. package/src/api/controllers/dev.js +4 -1
  243. package/src/api/controllers/query.js +29 -81
  244. package/src/api/controllers/row/ExternalRequest.ts +47 -16
  245. package/src/api/controllers/row/external.js +4 -1
  246. package/src/api/controllers/row/utils.js +8 -11
  247. package/src/api/controllers/table/external.js +307 -0
  248. package/src/api/controllers/table/index.js +47 -137
  249. package/src/api/controllers/table/internal.js +155 -0
  250. package/src/api/controllers/table/utils.js +74 -33
  251. package/src/api/controllers/user.js +132 -13
  252. package/src/api/controllers/view/exporters.js +5 -0
  253. package/src/api/controllers/view/index.js +15 -2
  254. package/src/api/routes/query.js +1 -0
  255. package/src/api/routes/table.js +11 -0
  256. package/src/api/routes/tests/datasource.spec.js +2 -2
  257. package/src/api/routes/tests/misc.spec.js +5 -1
  258. package/src/api/routes/tests/query.spec.js +0 -1
  259. package/src/api/routes/user.js +5 -0
  260. package/src/app.ts +2 -10
  261. package/src/automations/bullboard.js +28 -11
  262. package/src/automations/tests/automation.spec.js +3 -4
  263. package/src/automations/triggers.js +7 -3
  264. package/src/automations/utils.js +12 -2
  265. package/src/constants/index.js +22 -0
  266. package/src/definitions/common.ts +7 -1
  267. package/src/definitions/datasource.ts +10 -3
  268. package/src/environment.js +15 -0
  269. package/src/integrations/airtable.ts +2 -1
  270. package/src/integrations/arangodb.ts +2 -1
  271. package/src/integrations/base/IntegrationBase.ts +6 -0
  272. package/src/integrations/base/datasourcePlus.ts +9 -0
  273. package/src/integrations/base/sql.ts +362 -222
  274. package/src/integrations/base/sqlTable.ts +180 -0
  275. package/src/integrations/base/utils.ts +22 -0
  276. package/src/integrations/couchdb.ts +2 -1
  277. package/src/integrations/dynamodb.ts +2 -1
  278. package/src/integrations/elasticsearch.ts +2 -1
  279. package/src/integrations/index.ts +7 -0
  280. package/src/integrations/microsoftSqlServer.ts +145 -13
  281. package/src/integrations/mongodb.ts +2 -1
  282. package/src/integrations/mysql.ts +20 -94
  283. package/src/integrations/oracle.ts +445 -0
  284. package/src/integrations/postgres.ts +45 -35
  285. package/src/integrations/rest.ts +2 -1
  286. package/src/integrations/s3.ts +2 -1
  287. package/src/integrations/tests/microsoftSqlServer.spec.js +22 -15
  288. package/src/integrations/tests/oracle.spec.js +94 -0
  289. package/src/integrations/tests/postgres.spec.js +4 -0
  290. package/src/integrations/utils.ts +74 -8
  291. package/src/middleware/authorized.js +26 -18
  292. package/src/middleware/builder.js +4 -1
  293. package/src/middleware/tests/authorized.spec.js +2 -0
  294. package/src/tests/utilities/TestConfiguration.js +2 -1
  295. package/src/{automations/thread.js → threads/automation.js} +27 -8
  296. package/src/threads/index.js +66 -0
  297. package/src/threads/query.js +66 -0
  298. package/src/utilities/csvParser.js +48 -5
  299. package/src/utilities/global.js +7 -2
  300. package/src/utilities/index.js +11 -0
  301. package/src/utilities/queue/inMemoryQueue.js +7 -0
  302. package/src/utilities/scriptRunner.js +4 -1
  303. package/src/utilities/tests/__snapshots__/csvParser.spec.js.snap +0 -6
  304. package/src/utilities/tests/csvParser.spec.js +3 -0
  305. package/tsconfig.json +1 -1
  306. package/builder/assets/index.10556cc1.js +0 -201
  307. package/builder/assets/index.7469e1e4.css +0 -29
  308. package/builder/assets/vendor.278a305c.js +0 -9
  309. package/builder/assets/vendor.d75d5eb7.css +0 -1
@@ -26,6 +26,9 @@ const { clientLibraryPath, stringToReadStream } = require("../../utilities");
26
26
  const { getAllLocks } = require("../../utilities/redis");
27
27
  const { updateClientLibrary, backupClientLibrary, revertClientLibrary, } = require("../../utilities/fileSystem/clientLibrary");
28
28
  const { getTenantId, isMultiTenant } = require("@budibase/auth/tenancy");
29
+ const { syncGlobalUsers } = require("./user");
30
+ const { app: appCache } = require("@budibase/auth/cache");
31
+ const { cleanupAutomations } = require("../../automations/utils");
29
32
  const URL_REGEX_SLASH = /\/|\\/g;
30
33
  // utility function, need to do away with this
31
34
  function getLayouts(db) {
@@ -213,6 +216,7 @@ exports.create = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
213
216
  if (!env.isTest()) {
214
217
  yield createApp(appId);
215
218
  }
219
+ yield appCache.invalidateAppMetadata(appId, newApplication);
216
220
  ctx.status = 200;
217
221
  ctx.body = newApplication;
218
222
  });
@@ -267,8 +271,12 @@ exports.delete = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
267
271
  if (!env.isTest() && !ctx.query.unpublish) {
268
272
  yield deleteApp(ctx.params.appId);
269
273
  }
274
+ if (ctx.query && ctx.query.unpublish) {
275
+ yield cleanupAutomations(ctx.params.appId);
276
+ }
270
277
  // make sure the app/role doesn't stick around after the app has been deleted
271
278
  yield removeAppFromUserRoles(ctx, ctx.params.appId);
279
+ yield appCache.invalidateAppMetadata(ctx.params.appId);
272
280
  ctx.status = 200;
273
281
  ctx.body = result;
274
282
  });
@@ -277,6 +285,7 @@ exports.sync = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
277
285
  if (!isDevAppID(appId)) {
278
286
  ctx.throw(400, "This action cannot be performed for production apps");
279
287
  }
288
+ // replicate prod to dev
280
289
  const prodAppId = getDeployedAppID(appId);
281
290
  try {
282
291
  const prodDb = new CouchDB(prodAppId, { skip_setup: true });
@@ -307,6 +316,8 @@ exports.sync = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
307
316
  catch (err) {
308
317
  error = err;
309
318
  }
319
+ // sync the users
320
+ yield syncGlobalUsers(appId);
310
321
  if (error) {
311
322
  ctx.throw(400, error);
312
323
  }
@@ -327,7 +338,10 @@ const updateAppPackage = (ctx, appPackage, appId) => __awaiter(void 0, void 0, v
327
338
  // the locked by property is attached by server but generated from
328
339
  // Redis, shouldn't ever store it
329
340
  delete newAppPackage.lockedBy;
330
- return yield db.put(newAppPackage);
341
+ const response = yield db.put(newAppPackage);
342
+ // remove any cached metadata, so that it will be updated
343
+ yield appCache.invalidateAppMetadata(appId);
344
+ return response;
331
345
  });
332
346
  const createEmptyAppPackage = (ctx, app) => __awaiter(void 0, void 0, void 0, function* () {
333
347
  const db = new CouchDB(app.appId);
@@ -22,6 +22,8 @@ exports.fetchSelf = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
22
22
  return;
23
23
  }
24
24
  const user = yield getFullUser(ctx, userId);
25
+ // this shouldn't be returned by the app self
26
+ delete user.roles;
25
27
  if (appId) {
26
28
  const db = new CouchDB(appId);
27
29
  // remove the full roles structure
@@ -40,9 +42,7 @@ exports.fetchSelf = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
40
42
  }
41
43
  // user has a role of some sort, return them
42
44
  else if (err.status === 404) {
43
- const metadata = {
44
- _id: userId,
45
- };
45
+ const metadata = Object.assign(Object.assign({}, user), { _id: userId });
46
46
  const dbResp = yield db.put(metadata);
47
47
  user._rev = dbResp.rev;
48
48
  response = user;
@@ -10,8 +10,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  const CouchDB = require("../../db");
12
12
  const { generateDatasourceID, getDatasourceParams, getQueryParams, DocumentTypes, BudibaseInternalDB, getTableParams, } = require("../../db/utils");
13
+ const { BuildSchemaErrors, InvalidColumns } = require("../../constants");
13
14
  const { integrations } = require("../../integrations");
14
- const { makeExternalQuery } = require("./row/utils");
15
+ const { getDatasourceAndQuery } = require("./row/utils");
15
16
  exports.fetch = function (ctx) {
16
17
  return __awaiter(this, void 0, void 0, function* () {
17
18
  const database = new CouchDB(ctx.appId);
@@ -33,11 +34,15 @@ exports.buildSchemaFromDb = function (ctx) {
33
34
  return __awaiter(this, void 0, void 0, function* () {
34
35
  const db = new CouchDB(ctx.appId);
35
36
  const datasource = yield db.get(ctx.params.datasourceId);
36
- const tables = yield buildSchemaHelper(datasource);
37
+ const { tables, error } = yield buildSchemaHelper(datasource);
37
38
  datasource.entities = tables;
38
- const response = yield db.put(datasource);
39
- datasource._rev = response.rev;
40
- ctx.body = datasource;
39
+ const dbResp = yield db.put(datasource);
40
+ datasource._rev = dbResp.rev;
41
+ const response = { datasource };
42
+ if (error) {
43
+ response.error = error;
44
+ }
45
+ ctx.body = response;
41
46
  });
42
47
  };
43
48
  exports.update = function (ctx) {
@@ -57,7 +62,7 @@ exports.update = function (ctx) {
57
62
  }
58
63
  ctx.status = 200;
59
64
  ctx.message = "Datasource saved successfully.";
60
- ctx.body = datasource;
65
+ ctx.body = { datasource };
61
66
  });
62
67
  };
63
68
  exports.save = function (ctx) {
@@ -66,12 +71,14 @@ exports.save = function (ctx) {
66
71
  const plus = ctx.request.body.datasource.plus;
67
72
  const fetchSchema = ctx.request.body.fetchSchema;
68
73
  const datasource = Object.assign({ _id: generateDatasourceID({ plus }), type: plus ? DocumentTypes.DATASOURCE_PLUS : DocumentTypes.DATASOURCE }, ctx.request.body.datasource);
74
+ let schemaError = null;
69
75
  if (fetchSchema) {
70
- let tables = yield buildSchemaHelper(datasource);
76
+ const { tables, error } = yield buildSchemaHelper(datasource);
77
+ schemaError = error;
71
78
  datasource.entities = tables;
72
79
  }
73
- const response = yield db.put(datasource);
74
- datasource._rev = response.rev;
80
+ const dbResp = yield db.put(datasource);
81
+ datasource._rev = dbResp.rev;
75
82
  // Drain connection pools when configuration is changed
76
83
  if (datasource.source) {
77
84
  const source = integrations[datasource.source];
@@ -79,17 +86,23 @@ exports.save = function (ctx) {
79
86
  yield source.pool.end();
80
87
  }
81
88
  }
82
- ctx.status = 200;
83
- ctx.message = "Datasource saved successfully.";
84
- ctx.body = datasource;
89
+ const response = { datasource };
90
+ if (schemaError) {
91
+ response.error = schemaError;
92
+ }
93
+ ctx.body = response;
85
94
  });
86
95
  };
87
96
  exports.destroy = function (ctx) {
88
97
  return __awaiter(this, void 0, void 0, function* () {
89
98
  const db = new CouchDB(ctx.appId);
90
99
  // Delete all queries for the datasource
91
- const rows = yield db.allDocs(getQueryParams(ctx.params.datasourceId, null));
92
- yield db.bulkDocs(rows.rows.map(row => (Object.assign(Object.assign({}, row.doc), { _deleted: true }))));
100
+ const queries = yield db.allDocs(getQueryParams(ctx.params.datasourceId, null));
101
+ yield db.bulkDocs(queries.rows.map(row => ({
102
+ _id: row.id,
103
+ _rev: row.value.rev,
104
+ _deleted: true,
105
+ })));
93
106
  // delete the datasource
94
107
  yield db.remove(ctx.params.datasourceId, ctx.params.revId);
95
108
  ctx.message = `Datasource deleted.`;
@@ -107,18 +120,56 @@ exports.query = function (ctx) {
107
120
  return __awaiter(this, void 0, void 0, function* () {
108
121
  const queryJson = ctx.request.body;
109
122
  try {
110
- ctx.body = yield makeExternalQuery(ctx.appId, queryJson);
123
+ ctx.body = yield getDatasourceAndQuery(ctx.appId, queryJson);
111
124
  }
112
125
  catch (err) {
113
126
  ctx.throw(400, err);
114
127
  }
115
128
  });
116
129
  };
130
+ function getErrorTables(errors, errorType) {
131
+ return Object.entries(errors)
132
+ .filter(entry => entry[1] === errorType)
133
+ .map(([name]) => name);
134
+ }
135
+ function updateError(error, newError, tables) {
136
+ if (!error) {
137
+ error = "";
138
+ }
139
+ if (error.length > 0) {
140
+ error += "\n";
141
+ }
142
+ error += `${newError} ${tables.join(", ")}`;
143
+ return error;
144
+ }
117
145
  const buildSchemaHelper = (datasource) => __awaiter(void 0, void 0, void 0, function* () {
118
146
  const Connector = integrations[datasource.source];
119
147
  // Connect to the DB and build the schema
120
148
  const connector = new Connector(datasource.config);
121
149
  yield connector.buildSchema(datasource._id, datasource.entities);
122
150
  datasource.entities = connector.tables;
123
- return connector.tables;
151
+ // make sure they all have a display name selected
152
+ for (let entity of Object.values(datasource.entities)) {
153
+ if (entity.primaryDisplay) {
154
+ continue;
155
+ }
156
+ const notAutoColumn = Object.values(entity.schema).find(schema => !schema.autocolumn);
157
+ if (notAutoColumn) {
158
+ entity.primaryDisplay = notAutoColumn.name;
159
+ }
160
+ }
161
+ const errors = connector.schemaErrors;
162
+ let error = null;
163
+ if (errors && Object.keys(errors).length > 0) {
164
+ const noKey = getErrorTables(errors, BuildSchemaErrors.NO_KEY);
165
+ const invalidCol = getErrorTables(errors, BuildSchemaErrors.INVALID_COLUMN);
166
+ if (noKey.length) {
167
+ error = updateError(error, "No primary key constraint found for the following:", noKey);
168
+ }
169
+ if (invalidCol.length) {
170
+ const invalidCols = Object.values(InvalidColumns).join(", ");
171
+ error = updateError(error, `Cannot use columns ${invalidCols} found in following:`, invalidCol);
172
+ }
173
+ }
174
+ return { tables: connector.tables, error };
124
175
  });
@@ -13,6 +13,7 @@ const Deployment = require("./Deployment");
13
13
  const { Replication, getDeployedAppID } = require("@budibase/auth/db");
14
14
  const { DocumentTypes, getAutomationParams } = require("../../../db/utils");
15
15
  const { disableAllCrons, enableCronTrigger, } = require("../../../automations/utils");
16
+ const { app: appCache } = require("@budibase/auth/cache");
16
17
  // the max time we can wait for an invalidation to complete before considering it failed
17
18
  const MAX_PENDING_TIME_MS = 30 * 60000;
18
19
  const DeploymentStatus = {
@@ -95,6 +96,7 @@ function deployApp(deployment) {
95
96
  appDoc.appId = productionAppId;
96
97
  appDoc.instance._id = productionAppId;
97
98
  yield db.put(appDoc);
99
+ yield appCache.invalidateAppMetadata(productionAppId);
98
100
  console.log("New app doc written successfully.");
99
101
  yield initDeployedApp(productionAppId);
100
102
  console.log("Deployed app initialised, setting deployment to successful");
@@ -16,6 +16,7 @@ const { request } = require("../../utilities/workerRequests");
16
16
  const { clearLock } = require("../../utilities/redis");
17
17
  const { Replication } = require("@budibase/auth").db;
18
18
  const { DocumentTypes } = require("../../db/utils");
19
+ const { app: appCache } = require("@budibase/auth/cache");
19
20
  function redirect(ctx, method, path = "global") {
20
21
  return __awaiter(this, void 0, void 0, function* () {
21
22
  const { devPath } = ctx.params;
@@ -25,7 +26,8 @@ function redirect(ctx, method, path = "global") {
25
26
  body: ctx.request.body,
26
27
  }, true));
27
28
  if (response.status !== 200) {
28
- ctx.throw(response.status, response.statusText);
29
+ const err = yield response.text();
30
+ ctx.throw(400, err);
29
31
  }
30
32
  const cookie = response.headers.get("set-cookie");
31
33
  if (cookie) {
@@ -102,6 +104,7 @@ exports.revert = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
102
104
  appDoc.appId = appId;
103
105
  appDoc.instance._id = appId;
104
106
  yield db.put(appDoc);
107
+ yield appCache.invalidateAppMetadata(appId);
105
108
  ctx.body = {
106
109
  message: "Reverted changes successfully.",
107
110
  };
@@ -11,10 +11,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  const { processString } = require("@budibase/string-templates");
12
12
  const CouchDB = require("../../db");
13
13
  const { generateQueryID, getQueryParams } = require("../../db/utils");
14
- const { integrations } = require("../../integrations");
15
14
  const { BaseQueryVerbs } = require("../../constants");
16
15
  const env = require("../../environment");
17
- const ScriptRunner = require("../../utilities/scriptRunner");
16
+ const { Thread, ThreadType } = require("../../threads");
17
+ const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 });
18
18
  // simple function to append "readable" to all read queries
19
19
  function enrichQueries(input) {
20
20
  const wasArray = Array.isArray(input);
@@ -26,38 +26,6 @@ function enrichQueries(input) {
26
26
  }
27
27
  return wasArray ? queries : queries[0];
28
28
  }
29
- function formatResponse(resp) {
30
- if (typeof resp === "string") {
31
- try {
32
- resp = JSON.parse(resp);
33
- }
34
- catch (err) {
35
- resp = { response: resp };
36
- }
37
- }
38
- return resp;
39
- }
40
- function runAndTransform(integration, queryVerb, enrichedQuery, transformer) {
41
- return __awaiter(this, void 0, void 0, function* () {
42
- let rows = formatResponse(yield integration[queryVerb](enrichedQuery));
43
- // transform as required
44
- if (transformer) {
45
- const runner = new ScriptRunner(transformer, { data: rows });
46
- rows = runner.execute();
47
- }
48
- // needs to an array for next step
49
- if (!Array.isArray(rows)) {
50
- rows = [rows];
51
- }
52
- // map into JSON if just raw primitive here
53
- if (rows.find(row => typeof row !== "object")) {
54
- rows = rows.map(value => ({ value }));
55
- }
56
- // get all the potential fields in the schema
57
- let keys = rows.flatMap(Object.keys);
58
- return { rows, keys };
59
- });
60
- }
61
29
  exports.fetch = function (ctx) {
62
30
  return __awaiter(this, void 0, void 0, function* () {
63
31
  const db = new CouchDB(ctx.appId);
@@ -94,7 +62,9 @@ function enrichQueryFields(fields, parameters = {}) {
94
62
  }
95
63
  else if (typeof fields[key] === "string") {
96
64
  // enrich string value as normal
97
- enrichedQuery[key] = yield processString(fields[key], parameters);
65
+ enrichedQuery[key] = yield processString(fields[key], parameters, {
66
+ noHelpers: true,
67
+ });
98
68
  }
99
69
  else {
100
70
  enrichedQuery[key] = fields[key];
@@ -133,21 +103,22 @@ exports.preview = function (ctx) {
133
103
  return __awaiter(this, void 0, void 0, function* () {
134
104
  const db = new CouchDB(ctx.appId);
135
105
  const datasource = yield db.get(ctx.request.body.datasourceId);
136
- const Integration = integrations[datasource.source];
137
- if (!Integration) {
138
- ctx.throw(400, "Integration type does not exist.");
139
- }
140
106
  const { fields, parameters, queryVerb, transformer } = ctx.request.body;
141
107
  const enrichedQuery = yield enrichQueryFields(fields, parameters);
142
- const integration = new Integration(datasource.config);
143
- const { rows, keys } = yield runAndTransform(integration, queryVerb, enrichedQuery, transformer);
144
- ctx.body = {
145
- rows,
146
- schemaFields: [...new Set(keys)],
147
- };
148
- // cleanup
149
- if (integration.end) {
150
- integration.end();
108
+ try {
109
+ const { rows, keys } = yield Runner.run({
110
+ datasource,
111
+ queryVerb,
112
+ query: enrichedQuery,
113
+ transformer,
114
+ });
115
+ ctx.body = {
116
+ rows,
117
+ schemaFields: [...new Set(keys)],
118
+ };
119
+ }
120
+ catch (err) {
121
+ ctx.throw(400, err);
151
122
  }
152
123
  });
153
124
  };
@@ -156,18 +127,19 @@ exports.execute = function (ctx) {
156
127
  const db = new CouchDB(ctx.appId);
157
128
  const query = yield db.get(ctx.params.queryId);
158
129
  const datasource = yield db.get(query.datasourceId);
159
- const Integration = integrations[datasource.source];
160
- if (!Integration) {
161
- ctx.throw(400, "Integration type does not exist.");
162
- }
163
130
  const enrichedQuery = yield enrichQueryFields(query.fields, ctx.request.body.parameters);
164
- const integration = new Integration(datasource.config);
165
131
  // call the relevant CRUD method on the integration class
166
- const { rows } = yield runAndTransform(integration, query.queryVerb, enrichedQuery, query.transformer);
167
- ctx.body = rows;
168
- // cleanup
169
- if (integration.end) {
170
- integration.end();
132
+ try {
133
+ const { rows } = yield Runner.run({
134
+ datasource,
135
+ queryVerb: query.queryVerb,
136
+ query: enrichedQuery,
137
+ transformer: query.transformer,
138
+ });
139
+ ctx.body = rows;
140
+ }
141
+ catch (err) {
142
+ ctx.throw(400, err);
171
143
  }
172
144
  });
173
145
  };
@@ -24,12 +24,13 @@ const datasource_1 = require("../../../definitions/datasource");
24
24
  const utils_1 = require("../../../integrations/utils");
25
25
  var External;
26
26
  (function (External) {
27
- const { makeExternalQuery } = require("./utils");
27
+ const { getDatasourceAndQuery } = require("./utils");
28
28
  const { DataSourceOperation, FieldTypes, RelationshipTypes, } = require("../../../constants");
29
29
  const { breakExternalTableId, isSQL } = require("../../../integrations/utils");
30
30
  const { processObjectSync } = require("@budibase/string-templates");
31
31
  const { cloneDeep } = require("lodash/fp");
32
32
  const CouchDB = require("../../../db");
33
+ const { processFormulas } = require("../../../utilities/rowProcessor/utils");
33
34
  function buildFilters(id, filters, table) {
34
35
  const primary = table.primary;
35
36
  // if passed in array need to copy for shifting etc
@@ -151,6 +152,21 @@ var External;
151
152
  thisRow._rev = "rev";
152
153
  return thisRow;
153
154
  }
155
+ function fixArrayTypes(row, table) {
156
+ for (let [fieldName, schema] of Object.entries(table.schema)) {
157
+ if (schema.type === FieldTypes.ARRAY &&
158
+ typeof row[fieldName] === "string") {
159
+ try {
160
+ row[fieldName] = JSON.parse(row[fieldName]);
161
+ }
162
+ catch (err) {
163
+ // couldn't convert back to array, ignore
164
+ delete row[fieldName];
165
+ }
166
+ }
167
+ }
168
+ return row;
169
+ }
154
170
  function isMany(field) {
155
171
  return (field.relationshipType && field.relationshipType.split("-")[0] === "many");
156
172
  }
@@ -182,7 +198,10 @@ var External;
182
198
  let newRow = {}, manyRelationships = [];
183
199
  for (let [key, field] of Object.entries(table.schema)) {
184
200
  // if set already, or not set just skip it
185
- if ((!row[key] && row[key] !== "") || newRow[key] || field.autocolumn) {
201
+ if (row[key] == null ||
202
+ newRow[key] ||
203
+ field.autocolumn ||
204
+ field.type === FieldTypes.FORMULA) {
186
205
  continue;
187
206
  }
188
207
  // if its an empty string then it means return the column to null (if possible)
@@ -278,7 +297,7 @@ var External;
278
297
  return rows;
279
298
  }
280
299
  outputProcessing(rows = [], table, relationships) {
281
- if (rows[0].read === true) {
300
+ if (!rows || rows.length === 0 || rows[0].read === true) {
282
301
  return [];
283
302
  }
284
303
  let finalRows = {};
@@ -290,12 +309,15 @@ var External;
290
309
  finalRows = this.updateRelationshipColumns(row, finalRows, relationships);
291
310
  continue;
292
311
  }
293
- const thisRow = basicProcessing(row, table);
312
+ const thisRow = fixArrayTypes(basicProcessing(row, table), table);
313
+ if (thisRow._id == null) {
314
+ throw "Unable to generate row ID for SQL rows";
315
+ }
294
316
  finalRows[thisRow._id] = thisRow;
295
317
  // do this at end once its been added to the final rows
296
318
  finalRows = this.updateRelationshipColumns(row, finalRows, relationships);
297
319
  }
298
- return Object.values(finalRows);
320
+ return processFormulas(table, Object.values(finalRows));
299
321
  }
300
322
  /**
301
323
  * Gets the list of relationship JSON structures based on the columns in the table,
@@ -359,7 +381,7 @@ var External;
359
381
  const tableId = isMany ? field.through : field.tableId;
360
382
  const manyKey = field.throughFrom || primaryKey;
361
383
  const fieldName = isMany ? manyKey : field.fieldName;
362
- const response = yield makeExternalQuery(this.appId, {
384
+ const response = yield getDatasourceAndQuery(this.appId, {
363
385
  endpoint: getEndpoint(tableId, DataSourceOperation.READ),
364
386
  filters: {
365
387
  equal: {
@@ -403,7 +425,7 @@ var External;
403
425
  ? DataSourceOperation.UPDATE
404
426
  : DataSourceOperation.CREATE;
405
427
  if (!found) {
406
- promises.push(makeExternalQuery(appId, {
428
+ promises.push(getDatasourceAndQuery(appId, {
407
429
  endpoint: getEndpoint(tableId, operation),
408
430
  // if we're doing many relationships then we're writing, only one response
409
431
  body,
@@ -430,7 +452,7 @@ var External;
430
452
  ? DataSourceOperation.DELETE
431
453
  : DataSourceOperation.UPDATE;
432
454
  const body = isMany ? null : { [colName]: null };
433
- promises.push(makeExternalQuery(this.appId, {
455
+ promises.push(getDatasourceAndQuery(this.appId, {
434
456
  endpoint: getEndpoint(tableId, op),
435
457
  body,
436
458
  filters,
@@ -449,13 +471,14 @@ var External;
449
471
  * is more performant and has the added benefit of protecting against this scenario.
450
472
  */
451
473
  buildFields(table, includeRelations = datasource_1.IncludeRelationships.INCLUDE) {
452
- function extractNonLinkFieldNames(table, existing = []) {
474
+ function extractRealFields(table, existing = []) {
453
475
  return Object.entries(table.schema)
454
476
  .filter(column => column[1].type !== FieldTypes.LINK &&
477
+ column[1].type !== FieldTypes.FORMULA &&
455
478
  !existing.find((field) => field === column[0]))
456
479
  .map(column => `${table.name}.${column[0]}`);
457
480
  }
458
- let fields = extractNonLinkFieldNames(table);
481
+ let fields = extractRealFields(table);
459
482
  for (let field of Object.values(table.schema)) {
460
483
  if (field.type !== FieldTypes.LINK || !includeRelations) {
461
484
  continue;
@@ -463,7 +486,7 @@ var External;
463
486
  const { tableName: linkTableName } = breakExternalTableId(field.tableId);
464
487
  const linkTable = this.tables[linkTableName];
465
488
  if (linkTable) {
466
- const linkedFields = extractNonLinkFieldNames(linkTable, fields);
489
+ const linkedFields = extractRealFields(linkTable, fields);
467
490
  fields = fields.concat(linkedFields);
468
491
  }
469
492
  }
@@ -487,7 +510,7 @@ var External;
487
510
  throw `Unable to process query, table "${tableName}" not defined.`;
488
511
  }
489
512
  // look for specific components of config which may not be considered acceptable
490
- let { id, row, filters, sort, paginate } = cleanupConfig(config, table);
513
+ let { id, row, filters, sort, paginate, rows } = cleanupConfig(config, table);
491
514
  filters = buildFilters(id, filters || {}, table);
492
515
  const relationships = this.buildRelationships(table);
493
516
  // clean up row on ingress using schema
@@ -511,7 +534,7 @@ var External;
511
534
  sort,
512
535
  paginate,
513
536
  relationships,
514
- body: row,
537
+ body: row || rows,
515
538
  // pass an id filter into extra, purely for mysql/returning
516
539
  extra: {
517
540
  idFilter: buildFilters(id || generateIdForRow(row, table), {}, table),
@@ -521,7 +544,7 @@ var External;
521
544
  },
522
545
  };
523
546
  // can't really use response right now
524
- const response = yield makeExternalQuery(appId, json);
547
+ const response = yield getDatasourceAndQuery(appId, json);
525
548
  // handle many to many relationships now if we know the ID (could be auto increment)
526
549
  if (operation !== DataSourceOperation.READ &&
527
550
  processed.manyRelationships) {
@@ -41,6 +41,7 @@ function handleRequest(appId, operation, tableId, opts = {}) {
41
41
  return new ExternalRequest(appId, operation, tableId, opts.datasource).run(opts);
42
42
  });
43
43
  }
44
+ exports.handleRequest = handleRequest;
44
45
  exports.patch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
45
46
  const appId = ctx.appId;
46
47
  const inputs = ctx.request.body;
@@ -64,7 +65,8 @@ exports.save = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
64
65
  exports.fetchView = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
65
66
  // there are no views in external data sources, shouldn't ever be called
66
67
  // for now just fetch
67
- ctx.params.tableId = ctx.params.viewName.split("all_")[1];
68
+ const split = ctx.params.viewName.split("all_");
69
+ ctx.params.tableId = split[1] ? split[1] : split[0];
68
70
  return exports.fetch(ctx);
69
71
  });
70
72
  exports.fetch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
@@ -14,8 +14,8 @@ const CouchDB = require("../../../db");
14
14
  const { InternalTables } = require("../../../db/utils");
15
15
  const userController = require("../user");
16
16
  const { FieldTypes } = require("../../../constants");
17
- const { integrations } = require("../../../integrations");
18
17
  const { processStringSync } = require("@budibase/string-templates");
18
+ const { makeExternalQuery } = require("../../../integrations/base/utils");
19
19
  validateJs.extend(validateJs.validators.datetime, {
20
20
  parse: function (value) {
21
21
  return new Date(value).getTime();
@@ -25,19 +25,11 @@ validateJs.extend(validateJs.validators.datetime, {
25
25
  return new Date(value).toISOString();
26
26
  },
27
27
  });
28
- exports.makeExternalQuery = (appId, json) => __awaiter(void 0, void 0, void 0, function* () {
28
+ exports.getDatasourceAndQuery = (appId, json) => __awaiter(void 0, void 0, void 0, function* () {
29
29
  const datasourceId = json.endpoint.datasourceId;
30
30
  const db = new CouchDB(appId);
31
31
  const datasource = yield db.get(datasourceId);
32
- const Integration = integrations[datasource.source];
33
- // query is the opinionated function
34
- if (Integration.prototype.query) {
35
- const integration = new Integration(datasource.config);
36
- return integration.query(json);
37
- }
38
- else {
39
- throw "Datasource does not support query.";
40
- }
32
+ return makeExternalQuery(datasource, json);
41
33
  });
42
34
  exports.findRow = (ctx, db, tableId, rowId) => __awaiter(void 0, void 0, void 0, function* () {
43
35
  let row;
@@ -73,7 +65,9 @@ exports.validate = ({ appId, tableId, row, table }) => __awaiter(void 0, void 0,
73
65
  }
74
66
  let res;
75
67
  // Validate.js doesn't seem to handle array
76
- if (table.schema[fieldName].type === FieldTypes.ARRAY) {
68
+ if (table.schema[fieldName].type === FieldTypes.ARRAY &&
69
+ row[fieldName] &&
70
+ row[fieldName].length) {
77
71
  row[fieldName].map(val => {
78
72
  if (!constraints.inclusion.includes(val)) {
79
73
  errors[fieldName] = "Field not in list";