@budibase/server 0.9.188 → 0.9.190-alpha.2

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 (307) hide show
  1. package/Dockerfile +7 -1
  2. package/__mocks__/mssql.ts +1 -1
  3. package/__mocks__/oracledb.ts +31 -0
  4. package/__mocks__/pg.ts +3 -0
  5. package/builder/assets/bb-space-man.5be51a45.svg +290 -0
  6. package/builder/assets/index.7d405e74.css +1 -0
  7. package/builder/assets/index.edea4fa5.js +1316 -0
  8. package/builder/assets/oracle.66592424.png +0 -0
  9. package/builder/assets/vendor.470042a4.js +152 -0
  10. package/builder/assets/vendor.5e1fe644.css +1 -0
  11. package/builder/index.html +4 -4
  12. package/coverage/clover.xml +1507 -1081
  13. package/coverage/coverage-final.json +93 -89
  14. package/coverage/lcov-report/api/controllers/analytics.js.html +2 -2
  15. package/coverage/lcov-report/api/controllers/apikeys.js.html +2 -2
  16. package/coverage/lcov-report/api/controllers/application.js.html +64 -13
  17. package/coverage/lcov-report/api/controllers/auth.js.html +19 -10
  18. package/coverage/lcov-report/api/controllers/automation.js.html +3 -3
  19. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  22. package/coverage/lcov-report/api/controllers/datasource.js.html +232 -28
  23. package/coverage/lcov-report/api/controllers/dev.js.html +16 -7
  24. package/coverage/lcov-report/api/controllers/hosting.js.html +10 -10
  25. package/coverage/lcov-report/api/controllers/index.html +91 -91
  26. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/layout.js.html +3 -3
  28. package/coverage/lcov-report/api/controllers/metadata.js.html +3 -3
  29. package/coverage/lcov-report/api/controllers/permission.js.html +3 -3
  30. package/coverage/lcov-report/api/controllers/query.js.html +53 -209
  31. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  32. package/coverage/lcov-report/api/controllers/routing.js.html +3 -3
  33. package/coverage/lcov-report/api/controllers/row/external.js.html +17 -8
  34. package/coverage/lcov-report/api/controllers/row/index.html +26 -26
  35. package/coverage/lcov-report/api/controllers/row/index.js.html +2 -2
  36. package/coverage/lcov-report/api/controllers/row/internal.js.html +9 -9
  37. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +2 -2
  38. package/coverage/lcov-report/api/controllers/row/utils.js.html +21 -30
  39. package/coverage/lcov-report/api/controllers/screen.js.html +2 -2
  40. package/coverage/lcov-report/api/controllers/script.js.html +3 -3
  41. package/coverage/lcov-report/api/controllers/table/external.js.html +1001 -0
  42. package/coverage/lcov-report/api/controllers/table/index.html +56 -26
  43. package/coverage/lcov-report/api/controllers/table/index.js.html +80 -350
  44. package/coverage/lcov-report/api/controllers/table/internal.js.html +545 -0
  45. package/coverage/lcov-report/api/controllers/table/utils.js.html +175 -52
  46. package/coverage/lcov-report/api/controllers/templates.js.html +4 -4
  47. package/coverage/lcov-report/api/controllers/user.js.html +390 -33
  48. package/coverage/lcov-report/api/controllers/view/exporters.js.html +19 -4
  49. package/coverage/lcov-report/api/controllers/view/index.html +22 -22
  50. package/coverage/lcov-report/api/controllers/view/index.js.html +52 -13
  51. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  52. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +3 -3
  53. package/coverage/lcov-report/api/controllers/webhook.js.html +4 -4
  54. package/coverage/lcov-report/api/index.html +1 -1
  55. package/coverage/lcov-report/api/index.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/dev.js.html +2 -2
  67. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/index.html +4 -4
  69. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/query.js.html +5 -2
  75. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/static.js.html +2 -2
  81. package/coverage/lcov-report/api/routes/table.js.html +35 -2
  82. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  83. package/coverage/lcov-report/api/routes/user.js.html +17 -2
  84. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  85. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  86. package/coverage/lcov-report/automations/actions.js.html +2 -2
  87. package/coverage/lcov-report/automations/automationUtils.js.html +4 -4
  88. package/coverage/lcov-report/automations/bullboard.js.html +71 -20
  89. package/coverage/lcov-report/automations/index.html +35 -50
  90. package/coverage/lcov-report/automations/index.js.html +2 -2
  91. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/discord.js.html +3 -3
  96. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/executeScript.js.html +3 -3
  98. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  99. package/coverage/lcov-report/automations/steps/index.html +14 -14
  100. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +3 -3
  102. package/coverage/lcov-report/automations/steps/queryRows.js.html +3 -3
  103. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  104. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  106. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  107. package/coverage/lcov-report/automations/steps/utils.js.html +7 -7
  108. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  110. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  111. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  112. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  113. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  114. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  115. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  116. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  117. package/coverage/lcov-report/automations/triggers.js.html +22 -10
  118. package/coverage/lcov-report/automations/utils.js.html +42 -12
  119. package/coverage/lcov-report/constants/index.html +5 -5
  120. package/coverage/lcov-report/constants/index.js.html +87 -21
  121. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  122. package/coverage/lcov-report/constants/screens.js.html +1 -1
  123. package/coverage/lcov-report/db/client.js.html +2 -2
  124. package/coverage/lcov-report/db/inMemoryView.js.html +2 -2
  125. package/coverage/lcov-report/db/index.html +2 -2
  126. package/coverage/lcov-report/db/index.js.html +1 -1
  127. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +6 -6
  128. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  129. package/coverage/lcov-report/db/linkedRows/index.js.html +5 -5
  130. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +6 -6
  131. package/coverage/lcov-report/db/newid.js.html +3 -3
  132. package/coverage/lcov-report/db/utils.js.html +57 -57
  133. package/coverage/lcov-report/events/AutomationEmitter.js.html +6 -6
  134. package/coverage/lcov-report/events/index.html +6 -6
  135. package/coverage/lcov-report/events/index.js.html +1 -1
  136. package/coverage/lcov-report/events/utils.js.html +5 -5
  137. package/coverage/lcov-report/index.html +106 -91
  138. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  139. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  140. package/coverage/lcov-report/middleware/appInfo.js.html +2 -2
  141. package/coverage/lcov-report/middleware/authorized.js.html +11 -8
  142. package/coverage/lcov-report/middleware/builder.js.html +16 -7
  143. package/coverage/lcov-report/middleware/currentapp.js.html +6 -6
  144. package/coverage/lcov-report/middleware/index.html +23 -23
  145. package/coverage/lcov-report/middleware/joi-validator.js.html +2 -2
  146. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  147. package/coverage/lcov-report/middleware/selfhost.js.html +2 -2
  148. package/coverage/lcov-report/middleware/usageQuota.js.html +4 -4
  149. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  150. package/coverage/lcov-report/{automations/thread.js.html → threads/automation.js.html} +90 -33
  151. package/coverage/lcov-report/threads/index.html +141 -0
  152. package/coverage/lcov-report/threads/index.js.html +278 -0
  153. package/coverage/lcov-report/threads/query.js.html +278 -0
  154. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  155. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  156. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  157. package/coverage/lcov-report/utilities/csvParser.js.html +144 -15
  158. package/coverage/lcov-report/utilities/global.js.html +26 -11
  159. package/coverage/lcov-report/utilities/index.html +48 -48
  160. package/coverage/lcov-report/utilities/index.js.html +47 -14
  161. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +30 -9
  162. package/coverage/lcov-report/utilities/queue/index.html +14 -14
  163. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  164. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  165. package/coverage/lcov-report/utilities/rowProcessor/index.html +4 -4
  166. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +2 -2
  167. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +3 -3
  168. package/coverage/lcov-report/utilities/scriptRunner.js.html +16 -7
  169. package/coverage/lcov-report/utilities/security.js.html +3 -3
  170. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  171. package/coverage/lcov-report/utilities/users.js.html +1 -1
  172. package/coverage/lcov-report/utilities/workerRequests.js.html +5 -5
  173. package/coverage/lcov.info +2495 -1737
  174. package/dist/api/controllers/application.js +15 -1
  175. package/dist/api/controllers/auth.js +3 -3
  176. package/dist/api/controllers/datasource.js +67 -16
  177. package/dist/api/controllers/deploy/index.js +2 -0
  178. package/dist/api/controllers/dev.js +4 -1
  179. package/dist/api/controllers/query.js +30 -58
  180. package/dist/api/controllers/row/ExternalRequest.js +78 -34
  181. package/dist/api/controllers/row/external.js +3 -1
  182. package/dist/api/controllers/row/utils.js +6 -12
  183. package/dist/api/controllers/table/external.js +249 -0
  184. package/dist/api/controllers/table/index.js +49 -123
  185. package/dist/api/controllers/table/internal.js +150 -0
  186. package/dist/api/controllers/table/utils.js +62 -28
  187. package/dist/api/controllers/user.js +123 -11
  188. package/dist/api/controllers/view/exporters.js +4 -0
  189. package/dist/api/controllers/view/index.js +14 -2
  190. package/dist/api/routes/query.js +1 -1
  191. package/dist/api/routes/table.js +7 -1
  192. package/dist/api/routes/user.js +2 -1
  193. package/dist/app.js +2 -11
  194. package/dist/automations/bullboard.js +37 -10
  195. package/dist/automations/triggers.js +7 -3
  196. package/dist/automations/utils.js +11 -2
  197. package/dist/constants/index.js +19 -0
  198. package/dist/definitions/datasource.js +5 -0
  199. package/dist/environment.js +13 -0
  200. package/dist/integrations/base/IntegrationBase.js +2 -0
  201. package/dist/integrations/base/datasourcePlus.js +2 -0
  202. package/dist/integrations/base/sql.js +353 -177
  203. package/dist/integrations/base/sqlTable.js +143 -0
  204. package/dist/integrations/base/utils.js +30 -0
  205. package/dist/integrations/index.js +6 -0
  206. package/dist/integrations/microsoftSqlServer.js +117 -9
  207. package/dist/integrations/mysql.js +16 -85
  208. package/dist/integrations/oracle.js +347 -0
  209. package/dist/integrations/postgres.js +35 -28
  210. package/dist/integrations/utils.js +71 -9
  211. package/dist/middleware/authorized.js +2 -1
  212. package/dist/middleware/builder.js +4 -1
  213. package/dist/package.json +12 -7
  214. package/dist/tests/utilities/TestConfiguration.js +2 -1
  215. package/dist/{automations/thread.js → threads/automation.js} +26 -8
  216. package/dist/threads/index.js +64 -0
  217. package/dist/threads/query.js +64 -0
  218. package/dist/tsconfig.tsbuildinfo +1 -1
  219. package/dist/utilities/csvParser.js +46 -5
  220. package/dist/utilities/global.js +6 -2
  221. package/dist/utilities/index.js +11 -0
  222. package/dist/utilities/queue/inMemoryQueue.js +8 -0
  223. package/dist/utilities/scriptRunner.js +4 -1
  224. package/package.json +13 -8
  225. package/scripts/dev/manage.js +1 -0
  226. package/scripts/integrations/mssql/data/Dockerfile +9 -0
  227. package/scripts/integrations/mssql/data/entrypoint.sh +24 -0
  228. package/scripts/integrations/mssql/data/setup.sql +54 -0
  229. package/scripts/integrations/mssql/docker-compose.yaml +12 -0
  230. package/scripts/integrations/mssql/reset.sh +3 -0
  231. package/scripts/integrations/oracle/docker-compose.yml +19 -0
  232. package/scripts/integrations/oracle/instantclient/linux/x86-64/basiclite-21.4.zip +0 -0
  233. package/scripts/integrations/oracle/instantclient/linux/x86-64/install.sh +23 -0
  234. package/scripts/integrations/oracle/oracle.md +90 -0
  235. package/scripts/integrations/postgres/docker-compose.yml +3 -3
  236. package/scripts/likeCypress.ts +33 -0
  237. package/src/api/controllers/application.js +18 -1
  238. package/src/api/controllers/auth.js +3 -0
  239. package/src/api/controllers/datasource.js +84 -16
  240. package/src/api/controllers/deploy/index.js +2 -0
  241. package/src/api/controllers/dev.js +4 -1
  242. package/src/api/controllers/query.js +29 -81
  243. package/src/api/controllers/row/ExternalRequest.ts +91 -36
  244. package/src/api/controllers/row/external.js +4 -1
  245. package/src/api/controllers/row/utils.js +8 -11
  246. package/src/api/controllers/table/external.js +307 -0
  247. package/src/api/controllers/table/index.js +47 -137
  248. package/src/api/controllers/table/internal.js +155 -0
  249. package/src/api/controllers/table/utils.js +74 -33
  250. package/src/api/controllers/user.js +132 -13
  251. package/src/api/controllers/view/exporters.js +5 -0
  252. package/src/api/controllers/view/index.js +15 -2
  253. package/src/api/routes/query.js +1 -0
  254. package/src/api/routes/table.js +11 -0
  255. package/src/api/routes/tests/datasource.spec.js +2 -2
  256. package/src/api/routes/tests/misc.spec.js +5 -1
  257. package/src/api/routes/tests/query.spec.js +0 -1
  258. package/src/api/routes/user.js +5 -0
  259. package/src/app.ts +2 -10
  260. package/src/automations/bullboard.js +28 -11
  261. package/src/automations/tests/automation.spec.js +3 -4
  262. package/src/automations/triggers.js +7 -3
  263. package/src/automations/utils.js +12 -2
  264. package/src/constants/index.js +22 -0
  265. package/src/definitions/common.ts +7 -1
  266. package/src/definitions/datasource.ts +10 -3
  267. package/src/environment.js +15 -0
  268. package/src/integrations/airtable.ts +2 -1
  269. package/src/integrations/arangodb.ts +2 -1
  270. package/src/integrations/base/IntegrationBase.ts +6 -0
  271. package/src/integrations/base/datasourcePlus.ts +9 -0
  272. package/src/integrations/base/sql.ts +377 -218
  273. package/src/integrations/base/sqlTable.ts +180 -0
  274. package/src/integrations/base/utils.ts +22 -0
  275. package/src/integrations/couchdb.ts +2 -1
  276. package/src/integrations/dynamodb.ts +2 -1
  277. package/src/integrations/elasticsearch.ts +2 -1
  278. package/src/integrations/index.ts +7 -0
  279. package/src/integrations/microsoftSqlServer.ts +145 -13
  280. package/src/integrations/mongodb.ts +2 -1
  281. package/src/integrations/mysql.ts +23 -95
  282. package/src/integrations/oracle.ts +458 -0
  283. package/src/integrations/postgres.ts +45 -35
  284. package/src/integrations/rest.ts +2 -1
  285. package/src/integrations/s3.ts +2 -1
  286. package/src/integrations/tests/microsoftSqlServer.spec.js +22 -15
  287. package/src/integrations/tests/oracle.spec.js +94 -0
  288. package/src/integrations/tests/postgres.spec.js +4 -0
  289. package/src/integrations/utils.ts +78 -8
  290. package/src/middleware/authorized.js +2 -1
  291. package/src/middleware/builder.js +4 -1
  292. package/src/tests/utilities/TestConfiguration.js +2 -1
  293. package/src/{automations/thread.js → threads/automation.js} +27 -8
  294. package/src/threads/index.js +66 -0
  295. package/src/threads/query.js +66 -0
  296. package/src/utilities/csvParser.js +48 -5
  297. package/src/utilities/global.js +7 -2
  298. package/src/utilities/index.js +11 -0
  299. package/src/utilities/queue/inMemoryQueue.js +7 -0
  300. package/src/utilities/scriptRunner.js +4 -1
  301. package/src/utilities/tests/__snapshots__/csvParser.spec.js.snap +0 -6
  302. package/src/utilities/tests/csvParser.spec.js +3 -0
  303. package/tsconfig.json +1 -1
  304. package/builder/assets/index.550fdba7.js +0 -201
  305. package/builder/assets/index.7469e1e4.css +0 -29
  306. package/builder/assets/vendor.278a305c.js +0 -9
  307. package/builder/assets/vendor.d75d5eb7.css +0 -1
@@ -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";
@@ -0,0 +1,249 @@
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
+ const CouchDB = require("../../../db");
12
+ const { buildExternalTableId, breakExternalTableId, } = require("../../../integrations/utils");
13
+ const { getTable, generateForeignKey, generateJunctionTableName, foreignKeyStructure, hasTypeChanged, } = require("./utils");
14
+ const { DataSourceOperation, FieldTypes, RelationshipTypes, } = require("../../../constants");
15
+ const { makeExternalQuery } = require("../../../integrations/base/utils");
16
+ const { cloneDeep } = require("lodash/fp");
17
+ const csvParser = require("../../../utilities/csvParser");
18
+ const { handleRequest } = require("../row/external");
19
+ function makeTableRequest(datasource, operation, table, tables, oldTable = null) {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ const json = {
22
+ endpoint: {
23
+ datasourceId: datasource._id,
24
+ entityId: table._id,
25
+ operation,
26
+ },
27
+ meta: {
28
+ tables,
29
+ },
30
+ table,
31
+ };
32
+ if (oldTable) {
33
+ json.meta.table = oldTable;
34
+ }
35
+ return makeExternalQuery(datasource, json);
36
+ });
37
+ }
38
+ function cleanupRelationships(table, tables, oldTable = null) {
39
+ const tableToIterate = oldTable ? oldTable : table;
40
+ // clean up relationships in couch table schemas
41
+ for (let [key, schema] of Object.entries(tableToIterate.schema)) {
42
+ if (schema.type === FieldTypes.LINK &&
43
+ (!oldTable || table.schema[key] == null)) {
44
+ const relatedTable = Object.values(tables).find(table => table._id === schema.tableId);
45
+ const foreignKey = schema.foreignKey;
46
+ if (!relatedTable || !foreignKey) {
47
+ continue;
48
+ }
49
+ for (let [relatedKey, relatedSchema] of Object.entries(relatedTable.schema)) {
50
+ if (relatedSchema.type === FieldTypes.LINK &&
51
+ relatedSchema.fieldName === foreignKey) {
52
+ delete relatedTable.schema[relatedKey];
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+ function getDatasourceId(table) {
59
+ if (!table) {
60
+ throw "No table supplied";
61
+ }
62
+ if (table.sourceId) {
63
+ return table.sourceId;
64
+ }
65
+ return breakExternalTableId(table._id).datasourceId;
66
+ }
67
+ function otherRelationshipType(type) {
68
+ if (type === RelationshipTypes.MANY_TO_MANY) {
69
+ return RelationshipTypes.MANY_TO_MANY;
70
+ }
71
+ return type === RelationshipTypes.ONE_TO_MANY
72
+ ? RelationshipTypes.MANY_TO_ONE
73
+ : RelationshipTypes.ONE_TO_MANY;
74
+ }
75
+ function generateManyLinkSchema(datasource, column, table, relatedTable) {
76
+ const primary = table.name + table.primary[0];
77
+ const relatedPrimary = relatedTable.name + relatedTable.primary[0];
78
+ const jcTblName = generateJunctionTableName(column, table, relatedTable);
79
+ // first create the new table
80
+ const junctionTable = {
81
+ _id: buildExternalTableId(datasource._id, jcTblName),
82
+ name: jcTblName,
83
+ primary: [primary, relatedPrimary],
84
+ constrained: [primary, relatedPrimary],
85
+ schema: {
86
+ [primary]: foreignKeyStructure(primary, {
87
+ toTable: table.name,
88
+ toKey: table.primary[0],
89
+ }),
90
+ [relatedPrimary]: foreignKeyStructure(relatedPrimary, {
91
+ toTable: relatedTable.name,
92
+ toKey: relatedTable.primary[0],
93
+ }),
94
+ },
95
+ };
96
+ column.through = junctionTable._id;
97
+ column.throughFrom = primary;
98
+ column.throughTo = relatedPrimary;
99
+ column.fieldName = relatedPrimary;
100
+ return junctionTable;
101
+ }
102
+ function generateLinkSchema(column, table, relatedTable, type) {
103
+ const isOneSide = type === RelationshipTypes.ONE_TO_MANY;
104
+ const primary = isOneSide ? relatedTable.primary[0] : table.primary[0];
105
+ // generate a foreign key
106
+ const foreignKey = generateForeignKey(column, relatedTable);
107
+ column.relationshipType = type;
108
+ column.foreignKey = isOneSide ? foreignKey : primary;
109
+ column.fieldName = isOneSide ? primary : foreignKey;
110
+ return foreignKey;
111
+ }
112
+ function generateRelatedSchema(linkColumn, table, relatedTable, columnName) {
113
+ // generate column for other table
114
+ const relatedSchema = cloneDeep(linkColumn);
115
+ // swap them from the main link
116
+ if (linkColumn.foreignKey) {
117
+ relatedSchema.fieldName = linkColumn.foreignKey;
118
+ relatedSchema.foreignKey = linkColumn.fieldName;
119
+ }
120
+ // is many to many
121
+ else {
122
+ // don't need to copy through, already got it
123
+ relatedSchema.fieldName = linkColumn.throughFrom;
124
+ relatedSchema.throughTo = linkColumn.throughFrom;
125
+ relatedSchema.throughFrom = linkColumn.throughTo;
126
+ }
127
+ relatedSchema.relationshipType = otherRelationshipType(linkColumn.relationshipType);
128
+ relatedSchema.tableId = relatedTable._id;
129
+ relatedSchema.name = columnName;
130
+ table.schema[columnName] = relatedSchema;
131
+ }
132
+ function isRelationshipSetup(column) {
133
+ return column.foreignKey || column.through;
134
+ }
135
+ exports.save = function (ctx) {
136
+ return __awaiter(this, void 0, void 0, function* () {
137
+ const appId = ctx.appId;
138
+ const table = ctx.request.body;
139
+ // can't do this right now
140
+ delete table.dataImport;
141
+ const datasourceId = getDatasourceId(ctx.request.body);
142
+ // table doesn't exist already, note that it is created
143
+ if (!table._id) {
144
+ table.created = true;
145
+ }
146
+ let tableToSave = Object.assign({ type: "table", _id: buildExternalTableId(datasourceId, table.name) }, table);
147
+ let oldTable;
148
+ if (ctx.request.body && ctx.request.body._id) {
149
+ oldTable = yield getTable(appId, ctx.request.body._id);
150
+ }
151
+ if (hasTypeChanged(tableToSave, oldTable)) {
152
+ ctx.throw(400, "A column type has changed.");
153
+ }
154
+ const db = new CouchDB(appId);
155
+ const datasource = yield db.get(datasourceId);
156
+ const oldTables = cloneDeep(datasource.entities);
157
+ const tables = datasource.entities;
158
+ const extraTablesToUpdate = [];
159
+ // check if relations need setup
160
+ for (let schema of Object.values(tableToSave.schema)) {
161
+ if (schema.type !== FieldTypes.LINK || isRelationshipSetup(schema)) {
162
+ continue;
163
+ }
164
+ const relatedTable = Object.values(tables).find(table => table._id === schema.tableId);
165
+ const relatedColumnName = schema.fieldName;
166
+ const relationType = schema.relationshipType;
167
+ if (relationType === RelationshipTypes.MANY_TO_MANY) {
168
+ const junctionTable = generateManyLinkSchema(datasource, schema, table, relatedTable);
169
+ if (tables[junctionTable.name]) {
170
+ throw "Junction table already exists, cannot create another relationship.";
171
+ }
172
+ tables[junctionTable.name] = junctionTable;
173
+ extraTablesToUpdate.push(junctionTable);
174
+ }
175
+ else {
176
+ const fkTable = relationType === RelationshipTypes.ONE_TO_MANY ? table : relatedTable;
177
+ const foreignKey = generateLinkSchema(schema, table, relatedTable, relationType);
178
+ fkTable.schema[foreignKey] = foreignKeyStructure(foreignKey);
179
+ if (fkTable.constrained == null) {
180
+ fkTable.constrained = [];
181
+ }
182
+ if (fkTable.constrained.indexOf(foreignKey) === -1) {
183
+ fkTable.constrained.push(foreignKey);
184
+ }
185
+ // foreign key is in other table, need to save it to external
186
+ if (fkTable._id !== table._id) {
187
+ extraTablesToUpdate.push(fkTable);
188
+ }
189
+ }
190
+ generateRelatedSchema(schema, relatedTable, table, relatedColumnName);
191
+ schema.main = true;
192
+ }
193
+ cleanupRelationships(tableToSave, tables, oldTable);
194
+ const operation = oldTable
195
+ ? DataSourceOperation.UPDATE_TABLE
196
+ : DataSourceOperation.CREATE_TABLE;
197
+ yield makeTableRequest(datasource, operation, tableToSave, tables, oldTable);
198
+ // update any extra tables (like foreign keys in other tables)
199
+ for (let extraTable of extraTablesToUpdate) {
200
+ const oldExtraTable = oldTables[extraTable.name];
201
+ let op = oldExtraTable
202
+ ? DataSourceOperation.UPDATE_TABLE
203
+ : DataSourceOperation.CREATE_TABLE;
204
+ yield makeTableRequest(datasource, op, extraTable, tables, oldExtraTable);
205
+ }
206
+ // make sure the constrained list, all still exist
207
+ if (Array.isArray(tableToSave.constrained)) {
208
+ tableToSave.constrained = tableToSave.constrained.filter(constraint => Object.keys(tableToSave.schema).includes(constraint));
209
+ }
210
+ // store it into couch now for budibase reference
211
+ datasource.entities[tableToSave.name] = tableToSave;
212
+ yield db.put(datasource);
213
+ return tableToSave;
214
+ });
215
+ };
216
+ exports.destroy = function (ctx) {
217
+ return __awaiter(this, void 0, void 0, function* () {
218
+ const appId = ctx.appId;
219
+ const tableToDelete = yield getTable(appId, ctx.params.tableId);
220
+ if (!tableToDelete || !tableToDelete.created) {
221
+ ctx.throw(400, "Cannot delete tables which weren't created in Budibase.");
222
+ }
223
+ const datasourceId = getDatasourceId(tableToDelete);
224
+ const db = new CouchDB(appId);
225
+ const datasource = yield db.get(datasourceId);
226
+ const tables = datasource.entities;
227
+ const operation = DataSourceOperation.DELETE_TABLE;
228
+ yield makeTableRequest(datasource, operation, tableToDelete, tables);
229
+ cleanupRelationships(tableToDelete, tables);
230
+ delete datasource.entities[tableToDelete.name];
231
+ yield db.put(datasource);
232
+ return tableToDelete;
233
+ });
234
+ };
235
+ exports.bulkImport = function (ctx) {
236
+ return __awaiter(this, void 0, void 0, function* () {
237
+ const appId = ctx.appId;
238
+ const table = yield getTable(appId, ctx.params.tableId);
239
+ const { dataImport } = ctx.request.body;
240
+ if (!dataImport || !dataImport.schema || !dataImport.csvString) {
241
+ ctx.throw(400, "Provided data import information is invalid.");
242
+ }
243
+ const rows = yield csvParser.transform(Object.assign(Object.assign({}, dataImport), { existingTable: table }));
244
+ yield handleRequest(appId, DataSourceOperation.BULK_CREATE, table._id, {
245
+ rows,
246
+ });
247
+ return table;
248
+ });
249
+ };
@@ -8,23 +8,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __rest = (this && this.__rest) || function (s, e) {
12
- var t = {};
13
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
- t[p] = s[p];
15
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
- t[p[i]] = s[p[i]];
19
- }
20
- return t;
21
- };
22
11
  const CouchDB = require("../../../db");
23
- const linkRows = require("../../../db/linkedRows");
12
+ const internal = require("./internal");
13
+ const external = require("./external");
24
14
  const csvParser = require("../../../utilities/csvParser");
25
- const { getRowParams, getTableParams, generateTableID, getDatasourceParams, BudibaseInternalDB, } = require("../../../db/utils");
26
- const { FieldTypes } = require("../../../constants");
27
- const { TableSaveFunctions, getTable } = require("./utils");
15
+ const { isExternalTable } = require("../../../integrations/utils");
16
+ const { getTableParams, getDatasourceParams, BudibaseInternalDB, } = require("../../../db/utils");
17
+ const { getTable } = require("./utils");
18
+ function pickApi({ tableId, table }) {
19
+ if (table && !tableId) {
20
+ tableId = table._id;
21
+ }
22
+ if (table && table.type === "external") {
23
+ return external;
24
+ }
25
+ else if (tableId && isExternalTable(tableId)) {
26
+ return external;
27
+ }
28
+ return internal;
29
+ }
30
+ // covers both internal and external
28
31
  exports.fetch = function (ctx) {
29
32
  return __awaiter(this, void 0, void 0, function* () {
30
33
  const db = new CouchDB(ctx.appId);
@@ -50,126 +53,49 @@ exports.find = function (ctx) {
50
53
  exports.save = function (ctx) {
51
54
  return __awaiter(this, void 0, void 0, function* () {
52
55
  const appId = ctx.appId;
53
- const db = new CouchDB(appId);
54
- const _a = ctx.request.body, { dataImport } = _a, rest = __rest(_a, ["dataImport"]);
55
- let tableToSave = Object.assign({ type: "table", _id: generateTableID(), views: {} }, rest);
56
- // if the table obj had an _id then it will have been retrieved
57
- let oldTable;
58
- if (ctx.request.body && ctx.request.body._id) {
59
- oldTable = yield db.get(ctx.request.body._id);
60
- }
61
- // saving a table is a complex operation, involving many different steps, this
62
- // has been broken out into a utility to make it more obvious/easier to manipulate
63
- const tableSaveFunctions = new TableSaveFunctions({
64
- db,
65
- ctx,
66
- oldTable,
67
- dataImport,
68
- });
69
- tableToSave = yield tableSaveFunctions.before(tableToSave);
70
- // make sure that types don't change of a column, have to remove
71
- // the column if you want to change the type
72
- if (oldTable && oldTable.schema) {
73
- for (let propKey of Object.keys(tableToSave.schema)) {
74
- let column = tableToSave.schema[propKey];
75
- let oldColumn = oldTable.schema[propKey];
76
- if (oldColumn && oldColumn.type === "internal") {
77
- oldColumn.type = "auto";
78
- }
79
- if (oldColumn && oldColumn.type !== column.type) {
80
- ctx.throw(400, "Cannot change the type of a column");
81
- }
82
- }
83
- }
84
- // Don't rename if the name is the same
85
- let { _rename } = tableToSave;
86
- /* istanbul ignore next */
87
- if (_rename && _rename.old === _rename.updated) {
88
- _rename = null;
89
- delete tableToSave._rename;
90
- }
91
- // rename row fields when table column is renamed
92
- /* istanbul ignore next */
93
- if (_rename && tableToSave.schema[_rename.updated].type === FieldTypes.LINK) {
94
- ctx.throw(400, "Cannot rename a linked column.");
95
- }
96
- tableToSave = yield tableSaveFunctions.mid(tableToSave);
97
- // update schema of non-statistics views when new columns are added
98
- for (let view in tableToSave.views) {
99
- const tableView = tableToSave.views[view];
100
- if (!tableView)
101
- continue;
102
- if (tableView.schema.group || tableView.schema.field)
103
- continue;
104
- tableView.schema = tableToSave.schema;
105
- }
106
- // update linked rows
107
- try {
108
- const linkResp = yield linkRows.updateLinks({
109
- appId,
110
- eventType: oldTable
111
- ? linkRows.EventType.TABLE_UPDATED
112
- : linkRows.EventType.TABLE_SAVE,
113
- table: tableToSave,
114
- oldTable: oldTable,
115
- });
116
- if (linkResp != null && linkResp._rev) {
117
- tableToSave._rev = linkResp._rev;
118
- }
119
- }
120
- catch (err) {
121
- ctx.throw(400, err);
122
- }
123
- // don't perform any updates until relationships have been
124
- // checked by the updateLinks function
125
- const updatedRows = tableSaveFunctions.getUpdatedRows();
126
- if (updatedRows && updatedRows.length !== 0) {
127
- yield db.bulkDocs(updatedRows);
128
- }
129
- const result = yield db.put(tableToSave);
130
- tableToSave._rev = result.rev;
131
- tableToSave = yield tableSaveFunctions.after(tableToSave);
132
- ctx.eventEmitter &&
133
- ctx.eventEmitter.emitTable(`table:save`, appId, tableToSave);
56
+ const table = ctx.request.body;
57
+ const savedTable = yield pickApi({ table }).save(ctx);
134
58
  ctx.status = 200;
135
- ctx.message = `Table ${ctx.request.body.name} saved successfully.`;
136
- ctx.body = tableToSave;
59
+ ctx.message = `Table ${table.name} saved successfully.`;
60
+ ctx.eventEmitter &&
61
+ ctx.eventEmitter.emitTable(`table:save`, appId, savedTable);
62
+ ctx.body = savedTable;
137
63
  });
138
64
  };
139
65
  exports.destroy = function (ctx) {
140
66
  return __awaiter(this, void 0, void 0, function* () {
141
67
  const appId = ctx.appId;
142
- const db = new CouchDB(appId);
143
- const tableToDelete = yield db.get(ctx.params.tableId);
144
- // Delete all rows for that table
145
- const rows = yield db.allDocs(getRowParams(ctx.params.tableId, null, {
146
- include_docs: true,
147
- }));
148
- yield db.bulkDocs(rows.rows.map(row => (Object.assign(Object.assign({}, row.doc), { _deleted: true }))));
149
- // update linked rows
150
- yield linkRows.updateLinks({
151
- appId,
152
- eventType: linkRows.EventType.TABLE_DELETE,
153
- table: tableToDelete,
154
- });
155
- // don't remove the table itself until very end
156
- yield db.remove(tableToDelete);
157
- // remove table search index
158
- const currentIndexes = yield db.getIndexes();
159
- const existingIndex = currentIndexes.indexes.find(existing => existing.name === `search:${ctx.params.tableId}`);
160
- if (existingIndex) {
161
- yield db.deleteIndex(existingIndex);
162
- }
68
+ const tableId = ctx.params.tableId;
69
+ const deletedTable = yield pickApi({ tableId }).destroy(ctx);
163
70
  ctx.eventEmitter &&
164
- ctx.eventEmitter.emitTable(`table:delete`, appId, tableToDelete);
71
+ ctx.eventEmitter.emitTable(`table:delete`, appId, deletedTable);
165
72
  ctx.status = 200;
166
- ctx.body = { message: `Table ${ctx.params.tableId} deleted.` };
73
+ ctx.body = { message: `Table ${tableId} deleted.` };
74
+ });
75
+ };
76
+ exports.bulkImport = function (ctx) {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ const tableId = ctx.params.tableId;
79
+ yield pickApi({ tableId }).bulkImport(ctx);
80
+ // right now we don't trigger anything for bulk import because it
81
+ // can only be done in the builder, but in the future we may need to
82
+ // think about events for bulk items
83
+ ctx.status = 200;
84
+ ctx.body = { message: `Bulk rows created.` };
167
85
  });
168
86
  };
169
87
  exports.validateCSVSchema = function (ctx) {
170
88
  return __awaiter(this, void 0, void 0, function* () {
171
- const { csvString, schema = {} } = ctx.request.body;
172
- const result = yield csvParser.parse(csvString, schema);
89
+ // tableId being specified means its an import to an existing table
90
+ const { csvString, schema = {}, tableId } = ctx.request.body;
91
+ let existingTable;
92
+ if (tableId) {
93
+ existingTable = yield getTable(ctx.appId, tableId);
94
+ }
95
+ let result = yield csvParser.parse(csvString, schema);
96
+ if (existingTable) {
97
+ result = csvParser.updateSchema({ schema: result, existingTable });
98
+ }
173
99
  ctx.body = { schema: result };
174
100
  });
175
101
  };
@@ -0,0 +1,150 @@
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
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ const CouchDB = require("../../../db");
23
+ const linkRows = require("../../../db/linkedRows");
24
+ const { getRowParams, generateTableID } = require("../../../db/utils");
25
+ const { FieldTypes } = require("../../../constants");
26
+ const { TableSaveFunctions, hasTypeChanged, getTable, handleDataImport, } = require("./utils");
27
+ exports.save = function (ctx) {
28
+ return __awaiter(this, void 0, void 0, function* () {
29
+ const appId = ctx.appId;
30
+ const db = new CouchDB(appId);
31
+ const _a = ctx.request.body, { dataImport } = _a, rest = __rest(_a, ["dataImport"]);
32
+ let tableToSave = Object.assign({ type: "table", _id: generateTableID(), views: {} }, rest);
33
+ // if the table obj had an _id then it will have been retrieved
34
+ let oldTable;
35
+ if (ctx.request.body && ctx.request.body._id) {
36
+ oldTable = yield db.get(ctx.request.body._id);
37
+ }
38
+ if (hasTypeChanged(tableToSave, oldTable)) {
39
+ ctx.throw(400, "A column type has changed.");
40
+ }
41
+ // saving a table is a complex operation, involving many different steps, this
42
+ // has been broken out into a utility to make it more obvious/easier to manipulate
43
+ const tableSaveFunctions = new TableSaveFunctions({
44
+ db,
45
+ ctx,
46
+ oldTable,
47
+ dataImport,
48
+ });
49
+ tableToSave = yield tableSaveFunctions.before(tableToSave);
50
+ // make sure that types don't change of a column, have to remove
51
+ // the column if you want to change the type
52
+ if (oldTable && oldTable.schema) {
53
+ for (let propKey of Object.keys(tableToSave.schema)) {
54
+ let column = tableToSave.schema[propKey];
55
+ let oldColumn = oldTable.schema[propKey];
56
+ if (oldColumn && oldColumn.type === "internal") {
57
+ oldColumn.type = "auto";
58
+ }
59
+ if (oldColumn && oldColumn.type !== column.type) {
60
+ ctx.throw(400, "Cannot change the type of a column");
61
+ }
62
+ }
63
+ }
64
+ // Don't rename if the name is the same
65
+ let { _rename } = tableToSave;
66
+ /* istanbul ignore next */
67
+ if (_rename && _rename.old === _rename.updated) {
68
+ _rename = null;
69
+ delete tableToSave._rename;
70
+ }
71
+ // rename row fields when table column is renamed
72
+ /* istanbul ignore next */
73
+ if (_rename && tableToSave.schema[_rename.updated].type === FieldTypes.LINK) {
74
+ ctx.throw(400, "Cannot rename a linked column.");
75
+ }
76
+ tableToSave = yield tableSaveFunctions.mid(tableToSave);
77
+ // update schema of non-statistics views when new columns are added
78
+ for (let view in tableToSave.views) {
79
+ const tableView = tableToSave.views[view];
80
+ if (!tableView)
81
+ continue;
82
+ if (tableView.schema.group || tableView.schema.field)
83
+ continue;
84
+ tableView.schema = tableToSave.schema;
85
+ }
86
+ // update linked rows
87
+ try {
88
+ const linkResp = yield linkRows.updateLinks({
89
+ appId,
90
+ eventType: oldTable
91
+ ? linkRows.EventType.TABLE_UPDATED
92
+ : linkRows.EventType.TABLE_SAVE,
93
+ table: tableToSave,
94
+ oldTable: oldTable,
95
+ });
96
+ if (linkResp != null && linkResp._rev) {
97
+ tableToSave._rev = linkResp._rev;
98
+ }
99
+ }
100
+ catch (err) {
101
+ ctx.throw(400, err);
102
+ }
103
+ // don't perform any updates until relationships have been
104
+ // checked by the updateLinks function
105
+ const updatedRows = tableSaveFunctions.getUpdatedRows();
106
+ if (updatedRows && updatedRows.length !== 0) {
107
+ yield db.bulkDocs(updatedRows);
108
+ }
109
+ const result = yield db.put(tableToSave);
110
+ tableToSave._rev = result.rev;
111
+ tableToSave = yield tableSaveFunctions.after(tableToSave);
112
+ return tableToSave;
113
+ });
114
+ };
115
+ exports.destroy = function (ctx) {
116
+ return __awaiter(this, void 0, void 0, function* () {
117
+ const appId = ctx.appId;
118
+ const db = new CouchDB(appId);
119
+ const tableToDelete = yield db.get(ctx.params.tableId);
120
+ // Delete all rows for that table
121
+ const rows = yield db.allDocs(getRowParams(ctx.params.tableId, null, {
122
+ include_docs: true,
123
+ }));
124
+ yield db.bulkDocs(rows.rows.map(row => (Object.assign(Object.assign({}, row.doc), { _deleted: true }))));
125
+ // update linked rows
126
+ yield linkRows.updateLinks({
127
+ appId,
128
+ eventType: linkRows.EventType.TABLE_DELETE,
129
+ table: tableToDelete,
130
+ });
131
+ // don't remove the table itself until very end
132
+ yield db.remove(tableToDelete);
133
+ // remove table search index
134
+ const currentIndexes = yield db.getIndexes();
135
+ const existingIndex = currentIndexes.indexes.find(existing => existing.name === `search:${ctx.params.tableId}`);
136
+ if (existingIndex) {
137
+ yield db.deleteIndex(existingIndex);
138
+ }
139
+ return tableToDelete;
140
+ });
141
+ };
142
+ exports.bulkImport = function (ctx) {
143
+ return __awaiter(this, void 0, void 0, function* () {
144
+ const appId = ctx.appId;
145
+ const table = yield getTable(appId, ctx.params.tableId);
146
+ const { dataImport } = ctx.request.body;
147
+ yield handleDataImport(appId, ctx.user, table, dataImport);
148
+ return table;
149
+ });
150
+ };