@budibase/server 1.0.49-alpha.0 → 1.0.49-alpha.4

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 (239) hide show
  1. package/builder/assets/{index.dd9e386f.css → index.83c0944f.css} +1 -1
  2. package/builder/assets/{index.8184eed9.js → index.f763d886.js} +206 -205
  3. package/builder/assets/{vendor.3bd2f661.js → vendor.d526bfe8.js} +1 -1
  4. package/builder/index.html +3 -3
  5. package/coverage/clover.xml +1743 -1610
  6. package/coverage/coverage-final.json +90 -89
  7. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/application.js.html +106 -106
  10. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/automation.js.html +21 -21
  12. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/datasource.js.html +16 -16
  16. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +27 -12
  18. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/layout.js.html +6 -6
  20. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  21. package/coverage/lcov-report/{migrations/usageQuotas/syncApps.js.html → api/controllers/migrations.js.html} +30 -45
  22. package/coverage/lcov-report/api/controllers/permission.js.html +15 -15
  23. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  24. package/coverage/lcov-report/api/controllers/query/index.js.html +19 -19
  25. package/coverage/lcov-report/api/controllers/query/validation.js.html +6 -6
  26. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  27. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/external.js.html +16 -16
  29. package/coverage/lcov-report/api/controllers/row/index.html +40 -25
  30. package/coverage/lcov-report/api/controllers/row/index.js.html +13 -13
  31. package/coverage/lcov-report/api/controllers/row/internal.js.html +83 -146
  32. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +41 -17
  33. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +551 -0
  34. package/coverage/lcov-report/api/controllers/row/utils.js.html +13 -13
  35. package/coverage/lcov-report/api/controllers/screen.js.html +7 -7
  36. package/coverage/lcov-report/api/controllers/script.js.html +4 -4
  37. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +629 -0
  38. package/coverage/lcov-report/api/controllers/table/external.js.html +12 -12
  39. package/coverage/lcov-report/api/controllers/table/index.html +45 -30
  40. package/coverage/lcov-report/api/controllers/table/index.js.html +23 -65
  41. package/coverage/lcov-report/api/controllers/table/internal.js.html +33 -15
  42. package/coverage/lcov-report/api/controllers/table/utils.js.html +161 -41
  43. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/user.js.html +20 -20
  45. package/coverage/lcov-report/api/controllers/view/exporters.js.html +4 -4
  46. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/index.js.html +14 -14
  48. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  49. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +7 -7
  50. package/coverage/lcov-report/api/controllers/webhook.js.html +15 -15
  51. package/coverage/lcov-report/api/index.html +1 -1
  52. package/coverage/lcov-report/api/index.js.html +3 -3
  53. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/index.html +22 -7
  65. package/coverage/lcov-report/api/routes/index.js.html +10 -4
  66. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  69. package/coverage/lcov-report/{migrations/usageQuotas/index.js.html → api/routes/migrations.js.html} +25 -55
  70. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  82. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  83. package/coverage/lcov-report/automations/actions.js.html +24 -24
  84. package/coverage/lcov-report/automations/automationUtils.js.html +5 -5
  85. package/coverage/lcov-report/automations/bullboard.js.html +16 -16
  86. package/coverage/lcov-report/automations/index.html +1 -1
  87. package/coverage/lcov-report/automations/index.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/bash.js.html +6 -6
  89. package/coverage/lcov-report/automations/steps/createRow.js.html +7 -7
  90. package/coverage/lcov-report/automations/steps/delay.js.html +4 -4
  91. package/coverage/lcov-report/automations/steps/deleteRow.js.html +7 -7
  92. package/coverage/lcov-report/automations/steps/discord.js.html +7 -7
  93. package/coverage/lcov-report/automations/steps/executeQuery.js.html +6 -6
  94. package/coverage/lcov-report/automations/steps/executeScript.js.html +6 -6
  95. package/coverage/lcov-report/automations/steps/filter.js.html +7 -7
  96. package/coverage/lcov-report/automations/steps/index.html +1 -1
  97. package/coverage/lcov-report/automations/steps/integromat.js.html +5 -5
  98. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +8 -8
  99. package/coverage/lcov-report/automations/steps/queryRows.js.html +10 -10
  100. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +5 -5
  101. package/coverage/lcov-report/automations/steps/serverLog.js.html +3 -3
  102. package/coverage/lcov-report/automations/steps/slack.js.html +5 -5
  103. package/coverage/lcov-report/automations/steps/updateRow.js.html +6 -6
  104. package/coverage/lcov-report/automations/steps/utils.js.html +3 -3
  105. package/coverage/lcov-report/automations/steps/zapier.js.html +5 -5
  106. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  107. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  108. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  110. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  111. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  112. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  113. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  114. package/coverage/lcov-report/automations/triggers.js.html +18 -18
  115. package/coverage/lcov-report/automations/utils.js.html +32 -32
  116. package/coverage/lcov-report/constants/index.html +5 -5
  117. package/coverage/lcov-report/constants/index.js.html +42 -27
  118. package/coverage/lcov-report/constants/layouts.js.html +5 -5
  119. package/coverage/lcov-report/constants/screens.js.html +4 -4
  120. package/coverage/lcov-report/db/client.js.html +18 -18
  121. package/coverage/lcov-report/db/inMemoryView.js.html +7 -7
  122. package/coverage/lcov-report/db/index.html +1 -1
  123. package/coverage/lcov-report/db/index.js.html +3 -3
  124. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +7 -7
  125. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  126. package/coverage/lcov-report/db/linkedRows/index.js.html +26 -29
  127. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +13 -13
  128. package/coverage/lcov-report/db/newid.js.html +4 -4
  129. package/coverage/lcov-report/db/utils.js.html +71 -71
  130. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  131. package/coverage/lcov-report/events/index.html +1 -1
  132. package/coverage/lcov-report/events/index.js.html +5 -5
  133. package/coverage/lcov-report/events/utils.js.html +3 -3
  134. package/coverage/lcov-report/index.html +61 -76
  135. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  136. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  137. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  138. package/coverage/lcov-report/middleware/authorized.js.html +1 -1
  139. package/coverage/lcov-report/middleware/builder.js.html +1 -1
  140. package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
  141. package/coverage/lcov-report/middleware/index.html +11 -11
  142. package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
  143. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  144. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  145. package/coverage/lcov-report/middleware/usageQuota.js.html +6 -12
  146. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  147. package/coverage/lcov-report/threads/automation.js.html +1 -1
  148. package/coverage/lcov-report/threads/index.html +1 -1
  149. package/coverage/lcov-report/threads/index.js.html +10 -10
  150. package/coverage/lcov-report/threads/query.js.html +1 -1
  151. package/coverage/lcov-report/threads/utils.js.html +14 -14
  152. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  153. package/coverage/lcov-report/utilities/budibaseDir.js.html +7 -7
  154. package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
  155. package/coverage/lcov-report/utilities/csvParser.js.html +6 -6
  156. package/coverage/lcov-report/utilities/global.js.html +14 -14
  157. package/coverage/lcov-report/utilities/index.html +1 -1
  158. package/coverage/lcov-report/utilities/index.js.html +24 -24
  159. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +8 -8
  160. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  161. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  162. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  163. package/coverage/lcov-report/utilities/rowProcessor/index.html +27 -27
  164. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +80 -44
  165. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +75 -27
  166. package/coverage/lcov-report/utilities/scriptRunner.js.html +5 -5
  167. package/coverage/lcov-report/utilities/security.js.html +8 -8
  168. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  169. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  170. package/coverage/lcov-report/utilities/usageQuota/index.js.html +10 -10
  171. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  172. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  173. package/coverage/lcov-report/utilities/users.js.html +5 -5
  174. package/coverage/lcov-report/utilities/workerRequests.js.html +12 -12
  175. package/coverage/lcov.info +2545 -2257
  176. package/dist/api/controllers/application.js +18 -20
  177. package/dist/api/controllers/migrations.js +21 -0
  178. package/dist/api/controllers/row/internal.js +30 -53
  179. package/dist/api/controllers/row/internalSearch.js +12 -4
  180. package/dist/api/controllers/row/staticFormula.js +147 -0
  181. package/dist/api/controllers/table/bulkFormula.js +160 -0
  182. package/dist/api/controllers/table/index.js +3 -6
  183. package/dist/api/controllers/table/internal.js +7 -0
  184. package/dist/api/controllers/table/utils.js +32 -10
  185. package/dist/api/routes/index.js +2 -0
  186. package/dist/api/routes/migrations.js +9 -0
  187. package/dist/app.js +35 -5
  188. package/dist/constants/index.js +4 -0
  189. package/dist/db/linkedRows/index.js +4 -5
  190. package/dist/environment.js +1 -0
  191. package/dist/middleware/usageQuota.js +0 -2
  192. package/dist/migrations/functions/appUrls.js +46 -0
  193. package/dist/migrations/functions/quotas1.js +50 -0
  194. package/dist/migrations/{usageQuotas → functions/usageQuotas}/index.js +6 -10
  195. package/dist/migrations/{usageQuotas → functions/usageQuotas}/syncApps.js +11 -5
  196. package/dist/migrations/{usageQuotas → functions/usageQuotas}/syncRows.js +14 -8
  197. package/dist/migrations/functions/userEmailViewCasing.js +24 -0
  198. package/dist/migrations/index.js +62 -0
  199. package/dist/package.json +4 -4
  200. package/dist/tests/utilities/TestConfiguration.js +3 -0
  201. package/dist/tsconfig.tsbuildinfo +1 -1
  202. package/dist/utilities/rowProcessor/index.js +18 -11
  203. package/dist/utilities/rowProcessor/utils.js +14 -4
  204. package/package.json +5 -5
  205. package/src/api/controllers/application.js +3 -3
  206. package/src/api/controllers/migrations.js +13 -0
  207. package/src/api/controllers/row/internal.js +29 -50
  208. package/src/api/controllers/row/internalSearch.js +12 -4
  209. package/src/api/controllers/row/staticFormula.js +157 -0
  210. package/src/api/controllers/table/bulkFormula.js +183 -0
  211. package/src/api/controllers/table/index.js +3 -17
  212. package/src/api/controllers/table/internal.js +7 -1
  213. package/src/api/controllers/table/utils.js +48 -8
  214. package/src/api/routes/index.js +2 -0
  215. package/src/api/routes/migrations.js +14 -0
  216. package/src/app.ts +18 -5
  217. package/src/constants/index.js +5 -0
  218. package/src/db/linkedRows/index.js +4 -5
  219. package/src/definitions/common.ts +3 -0
  220. package/src/environment.js +1 -0
  221. package/src/middleware/usageQuota.js +0 -2
  222. package/src/migrations/functions/appUrls.ts +34 -0
  223. package/src/migrations/functions/quotas1.ts +20 -0
  224. package/src/migrations/functions/tests/appUrls.spec.js +29 -0
  225. package/src/migrations/{tests/usageQuotas/index.spec.js → functions/tests/quotas1.spec.js} +5 -5
  226. package/src/migrations/functions/tests/userEmailViewCasing.spec.js +25 -0
  227. package/src/migrations/functions/usageQuotas/index.ts +8 -0
  228. package/src/migrations/{usageQuotas/syncApps.js → functions/usageQuotas/syncApps.ts} +3 -3
  229. package/src/migrations/{usageQuotas/syncRows.js → functions/usageQuotas/syncRows.ts} +5 -5
  230. package/src/migrations/{tests/usageQuotas → functions/usageQuotas/tests}/syncApps.spec.js +4 -4
  231. package/src/migrations/{tests/usageQuotas → functions/usageQuotas/tests}/syncRows.spec.js +4 -4
  232. package/src/migrations/functions/userEmailViewCasing.ts +13 -0
  233. package/src/migrations/index.ts +56 -0
  234. package/src/tests/utilities/TestConfiguration.js +4 -0
  235. package/src/utilities/rowProcessor/index.js +24 -12
  236. package/src/utilities/rowProcessor/utils.js +23 -7
  237. package/coverage/lcov-report/migrations/usageQuotas/index.html +0 -141
  238. package/coverage/lcov-report/migrations/usageQuotas/syncRows.js.html +0 -143
  239. package/src/migrations/usageQuotas/index.js +0 -24
@@ -49,24 +49,22 @@ function getUserRoleId(ctx) {
49
49
  ? BUILTIN_ROLE_IDS.PUBLIC
50
50
  : ctx.user.role._id;
51
51
  }
52
- function getAppUrl(ctx) {
53
- return __awaiter(this, void 0, void 0, function* () {
54
- // construct the url
55
- let url;
56
- if (ctx.request.body.url) {
57
- // if the url is provided, use that
58
- url = encodeURI(ctx.request.body.url);
59
- }
60
- else if (ctx.request.body.name) {
61
- // otherwise use the name
62
- url = encodeURI(`${ctx.request.body.name}`);
63
- }
64
- if (url) {
65
- url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase();
66
- }
67
- return url;
68
- });
69
- }
52
+ exports.getAppUrl = ctx => {
53
+ // construct the url
54
+ let url;
55
+ if (ctx.request.body.url) {
56
+ // if the url is provided, use that
57
+ url = encodeURI(ctx.request.body.url);
58
+ }
59
+ else if (ctx.request.body.name) {
60
+ // otherwise use the name
61
+ url = encodeURI(`${ctx.request.body.name}`);
62
+ }
63
+ if (url) {
64
+ url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase();
65
+ }
66
+ return url;
67
+ };
70
68
  const checkAppUrl = (ctx, apps, url, currentAppId) => {
71
69
  if (currentAppId) {
72
70
  apps = apps.filter(app => app.appId !== currentAppId);
@@ -183,7 +181,7 @@ exports.create = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
183
181
  const apps = yield getAllApps(CouchDB, { dev: true });
184
182
  const name = ctx.request.body.name;
185
183
  checkAppName(ctx, apps, name);
186
- const url = yield getAppUrl(ctx);
184
+ const url = exports.getAppUrl(ctx);
187
185
  checkAppUrl(ctx, apps, url);
188
186
  const { useTemplate, templateKey, templateString } = ctx.request.body;
189
187
  const instanceConfig = {
@@ -245,7 +243,7 @@ exports.update = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
245
243
  if (name) {
246
244
  checkAppName(ctx, apps, name, ctx.params.appId);
247
245
  }
248
- const url = yield getAppUrl(ctx);
246
+ const url = yield exports.getAppUrl(ctx);
249
247
  if (url) {
250
248
  checkAppUrl(ctx, apps, url, ctx.params.appId);
251
249
  ctx.request.body.url = url;
@@ -0,0 +1,21 @@
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 { migrate, MIGRATIONS } = require("../../migrations");
12
+ exports.migrate = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
13
+ const options = ctx.request.body;
14
+ // don't await as can take a while, just return
15
+ migrate(options);
16
+ ctx.status = 200;
17
+ });
18
+ exports.fetchDefinitions = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
19
+ ctx.body = MIGRATIONS;
20
+ ctx.status = 200;
21
+ });
@@ -21,11 +21,10 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  };
22
22
  const CouchDB = require("../../../db");
23
23
  const linkRows = require("../../../db/linkedRows");
24
- const { getRowParams, generateRowID, DocumentTypes, InternalTables, } = require("../../../db/utils");
24
+ const { generateRowID, getRowParams, DocumentTypes, InternalTables, } = require("../../../db/utils");
25
25
  const userController = require("../user");
26
- const { inputProcessing, outputProcessing, processAutoColumn, cleanupAttachments, } = require("../../../utilities/rowProcessor");
26
+ const { inputProcessing, outputProcessing, cleanupAttachments, } = require("../../../utilities/rowProcessor");
27
27
  const { FieldTypes } = require("../../../constants");
28
- const { isEqual } = require("lodash");
29
28
  const { validate, findRow } = require("./utils");
30
29
  const { fullSearch, paginatedSearch } = require("./internalSearch");
31
30
  const { getGlobalUsersFromMetadata } = require("../../../utilities/global");
@@ -33,59 +32,12 @@ const inMemoryViews = require("../../../db/inMemoryView");
33
32
  const env = require("../../../environment");
34
33
  const { migrateToInMemoryView, migrateToDesignView, getFromDesignDoc, getFromMemoryDoc, } = require("../view/utils");
35
34
  const { cloneDeep } = require("lodash/fp");
35
+ const { finaliseRow, updateRelatedFormula } = require("./staticFormula");
36
36
  const CALCULATION_TYPES = {
37
37
  SUM: "sum",
38
38
  COUNT: "count",
39
39
  STATS: "stats",
40
40
  };
41
- function storeResponse(ctx, db, row, oldTable, table) {
42
- return __awaiter(this, void 0, void 0, function* () {
43
- row.type = "row";
44
- // don't worry about rev, tables handle rev/lastID updates
45
- // if another row has been written since processing this will
46
- // handle the auto ID clash
47
- if (!isEqual(oldTable, table)) {
48
- try {
49
- yield db.put(table);
50
- }
51
- catch (err) {
52
- if (err.status === 409) {
53
- const updatedTable = yield db.get(table._id);
54
- let response = processAutoColumn(null, updatedTable, row, {
55
- reprocessing: true,
56
- });
57
- yield db.put(response.table);
58
- row = response.row;
59
- }
60
- else {
61
- throw err;
62
- }
63
- }
64
- }
65
- const response = yield db.put(row);
66
- row._rev = response.rev;
67
- // process the row before return, to include relationships
68
- row = yield outputProcessing(ctx, table, row, { squash: false });
69
- return { row, table };
70
- });
71
- }
72
- // doesn't do the outputProcessing
73
- function getRawTableData(ctx, db, tableId) {
74
- return __awaiter(this, void 0, void 0, function* () {
75
- let rows;
76
- if (tableId === InternalTables.USER_METADATA) {
77
- yield userController.fetchMetadata(ctx);
78
- rows = ctx.body;
79
- }
80
- else {
81
- const response = yield db.allDocs(getRowParams(tableId, null, {
82
- include_docs: true,
83
- }));
84
- rows = response.rows.map(row => row.doc);
85
- }
86
- return rows;
87
- });
88
- }
89
41
  function getView(db, viewName) {
90
42
  return __awaiter(this, void 0, void 0, function* () {
91
43
  let mainGetter = env.SELF_HOSTED ? getFromDesignDoc : getFromMemoryDoc;
@@ -114,6 +66,22 @@ function getView(db, viewName) {
114
66
  return viewInfo;
115
67
  });
116
68
  }
69
+ function getRawTableData(ctx, db, tableId) {
70
+ return __awaiter(this, void 0, void 0, function* () {
71
+ let rows;
72
+ if (tableId === InternalTables.USER_METADATA) {
73
+ yield userController.fetchMetadata(ctx);
74
+ rows = ctx.body;
75
+ }
76
+ else {
77
+ const response = yield db.allDocs(getRowParams(tableId, null, {
78
+ include_docs: true,
79
+ }));
80
+ rows = response.rows.map(row => row.doc);
81
+ }
82
+ return rows;
83
+ });
84
+ }
117
85
  exports.patch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
118
86
  const appId = ctx.appId;
119
87
  const db = new CouchDB(appId);
@@ -169,7 +137,10 @@ exports.patch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
169
137
  yield userController.updateMetadata(ctx);
170
138
  return { row: ctx.body, table };
171
139
  }
172
- return storeResponse(ctx, db, row, dbTable, table);
140
+ return finaliseRow(ctx.appId, table, row, {
141
+ oldTable: dbTable,
142
+ updateFormula: true,
143
+ });
173
144
  });
174
145
  exports.save = function (ctx) {
175
146
  return __awaiter(this, void 0, void 0, function* () {
@@ -198,7 +169,10 @@ exports.save = function (ctx) {
198
169
  tableId: row.tableId,
199
170
  table,
200
171
  });
201
- return storeResponse(ctx, db, row, dbTable, table);
172
+ return finaliseRow(ctx.appId, table, row, {
173
+ oldTable: dbTable,
174
+ updateFormula: true,
175
+ });
202
176
  });
203
177
  };
204
178
  exports.fetchView = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
@@ -290,6 +264,8 @@ exports.destroy = function (ctx) {
290
264
  });
291
265
  // remove any attachments that were on the row from object storage
292
266
  yield cleanupAttachments(appId, table, { row });
267
+ // remove any static formula
268
+ yield updateRelatedFormula(appId, table, row);
293
269
  let response;
294
270
  if (ctx.params.tableId === InternalTables.USER_METADATA) {
295
271
  ctx.params = {
@@ -333,6 +309,7 @@ exports.bulkDestroy = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
333
309
  }
334
310
  // remove any attachments that were on the rows from object storage
335
311
  yield cleanupAttachments(appId, table, { rows });
312
+ yield updateRelatedFormula(appId, table, rows);
336
313
  yield Promise.all(updates);
337
314
  return { response: { ok: true }, rows };
338
315
  });
@@ -34,19 +34,27 @@ class QueryBuilder {
34
34
  return this;
35
35
  }
36
36
  setLimit(limit) {
37
- this.limit = limit;
37
+ if (limit != null) {
38
+ this.limit = limit;
39
+ }
38
40
  return this;
39
41
  }
40
42
  setSort(sort) {
41
- this.sort = sort;
43
+ if (sort != null) {
44
+ this.sort = sort;
45
+ }
42
46
  return this;
43
47
  }
44
48
  setSortOrder(sortOrder) {
45
- this.sortOrder = sortOrder;
49
+ if (sortOrder != null) {
50
+ this.sortOrder = sortOrder;
51
+ }
46
52
  return this;
47
53
  }
48
54
  setSortType(sortType) {
49
- this.sortType = sortType;
55
+ if (sortType != null) {
56
+ this.sortType = sortType;
57
+ }
50
58
  return this;
51
59
  }
52
60
  setBookmark(bookmark) {
@@ -0,0 +1,147 @@
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 { getRowParams } = require("../../../db/utils");
13
+ const { outputProcessing, processAutoColumn, processFormulas, } = require("../../../utilities/rowProcessor");
14
+ const { FieldTypes, FormulaTypes } = require("../../../constants");
15
+ const { isEqual } = require("lodash");
16
+ const { cloneDeep } = require("lodash/fp");
17
+ /**
18
+ * This function runs through a list of enriched rows, looks at the rows which
19
+ * are related and then checks if they need the state of their formulas
20
+ * updated.
21
+ * NOTE: this will only for affect static formulas.
22
+ */
23
+ exports.updateRelatedFormula = (appId, table, enrichedRows) => __awaiter(void 0, void 0, void 0, function* () {
24
+ const db = new CouchDB(appId);
25
+ // no formula to update, we're done
26
+ if (!table.relatedFormula) {
27
+ return;
28
+ }
29
+ let promises = [];
30
+ for (let enrichedRow of Array.isArray(enrichedRows)
31
+ ? enrichedRows
32
+ : [enrichedRows]) {
33
+ // the related rows by tableId
34
+ let relatedRows = {};
35
+ for (let [key, field] of Object.entries(enrichedRow)) {
36
+ const columnDefinition = table.schema[key];
37
+ if (columnDefinition && columnDefinition.type === FieldTypes.LINK) {
38
+ const relatedTableId = columnDefinition.tableId;
39
+ if (!relatedRows[relatedTableId]) {
40
+ relatedRows[relatedTableId] = [];
41
+ }
42
+ relatedRows[relatedTableId] = relatedRows[relatedTableId].concat(field);
43
+ }
44
+ }
45
+ for (let tableId of table.relatedFormula) {
46
+ let relatedTable;
47
+ try {
48
+ // no rows to update, skip
49
+ if (!relatedRows[tableId] || relatedRows[tableId].length === 0) {
50
+ continue;
51
+ }
52
+ relatedTable = yield db.get(tableId);
53
+ }
54
+ catch (err) {
55
+ // no error scenario, table doesn't seem to exist anymore, ignore
56
+ }
57
+ for (let column of Object.values(relatedTable.schema)) {
58
+ // needs updated in related rows
59
+ if (column.type === FieldTypes.FORMULA &&
60
+ column.formulaType === FormulaTypes.STATIC) {
61
+ // re-enrich rows for all the related, don't update the related formula for them
62
+ promises = promises.concat(relatedRows[tableId].map(related => exports.finaliseRow(appId, relatedTable, related, {
63
+ updateFormula: false,
64
+ })));
65
+ }
66
+ }
67
+ }
68
+ }
69
+ yield Promise.all(promises);
70
+ });
71
+ exports.updateAllFormulasInTable = (appId, table) => __awaiter(void 0, void 0, void 0, function* () {
72
+ const db = new CouchDB(appId);
73
+ // start by getting the raw rows (which will be written back to DB after update)
74
+ let rows = (yield db.allDocs(getRowParams(table._id, null, {
75
+ include_docs: true,
76
+ }))).rows.map(row => row.doc);
77
+ // now enrich the rows, note the clone so that we have the base state of the
78
+ // rows so that we don't write any of the enriched information back
79
+ let enrichedRows = yield outputProcessing({ appId }, table, cloneDeep(rows), {
80
+ squash: false,
81
+ });
82
+ const updatedRows = [];
83
+ for (let row of rows) {
84
+ // find the enriched row, if found process the formulas
85
+ const enrichedRow = enrichedRows.find(enriched => enriched._id === row._id);
86
+ if (enrichedRow) {
87
+ const processed = processFormulas(table, cloneDeep(row), {
88
+ dynamic: false,
89
+ contextRows: enrichedRow,
90
+ });
91
+ // values have changed, need to add to bulk docs to update
92
+ if (!isEqual(processed, row)) {
93
+ updatedRows.push(processed);
94
+ }
95
+ }
96
+ }
97
+ yield db.bulkDocs(updatedRows);
98
+ });
99
+ /**
100
+ * This function runs at the end of the save/patch functions of the row controller, all this
101
+ * really does is enrich the row, handle any static formula processing, then return the enriched
102
+ * row. The reason we need to return the enriched row is that the automation row created trigger
103
+ * expects the row to be totally enriched/contain all relationships.
104
+ */
105
+ exports.finaliseRow = (appId, table, row, { oldTable, updateFormula } = { updateFormula: true }) => __awaiter(void 0, void 0, void 0, function* () {
106
+ const db = new CouchDB(appId);
107
+ row.type = "row";
108
+ // process the row before return, to include relationships
109
+ let enrichedRow = yield outputProcessing({ appId }, table, cloneDeep(row), {
110
+ squash: false,
111
+ });
112
+ // use enriched row to generate formulas for saving, specifically only use as context
113
+ row = processFormulas(table, row, {
114
+ dynamic: false,
115
+ contextRows: enrichedRow,
116
+ });
117
+ // don't worry about rev, tables handle rev/lastID updates
118
+ // if another row has been written since processing this will
119
+ // handle the auto ID clash
120
+ if (oldTable && !isEqual(oldTable, table)) {
121
+ try {
122
+ yield db.put(table);
123
+ }
124
+ catch (err) {
125
+ if (err.status === 409) {
126
+ const updatedTable = yield db.get(table._id);
127
+ let response = processAutoColumn(null, updatedTable, row, {
128
+ reprocessing: true,
129
+ });
130
+ yield db.put(response.table);
131
+ row = response.row;
132
+ }
133
+ else {
134
+ throw err;
135
+ }
136
+ }
137
+ }
138
+ const response = yield db.put(row);
139
+ // for response, calculate the formulas for the enriched row
140
+ enrichedRow._rev = response.rev;
141
+ enrichedRow = yield processFormulas(table, enrichedRow, { dynamic: false });
142
+ // this updates the related formulas in other rows based on the relations to this row
143
+ if (updateFormula) {
144
+ yield exports.updateRelatedFormula(appId, table, enrichedRow);
145
+ }
146
+ return { row: enrichedRow, table };
147
+ });
@@ -0,0 +1,160 @@
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 { FieldTypes, FormulaTypes } = require("../../../constants");
13
+ const { getAllInternalTables, clearColumns } = require("./utils");
14
+ const { doesContainStrings } = require("@budibase/string-templates");
15
+ const { cloneDeep } = require("lodash/fp");
16
+ const { isEqual, uniq } = require("lodash");
17
+ const { updateAllFormulasInTable } = require("../row/staticFormula");
18
+ function isStaticFormula(column) {
19
+ return (column.type === FieldTypes.FORMULA &&
20
+ column.formulaType === FormulaTypes.STATIC);
21
+ }
22
+ /**
23
+ * This retrieves the formula columns from a table schema that use a specified column name
24
+ * in the formula.
25
+ */
26
+ function getFormulaThatUseColumn(table, columnNames) {
27
+ let formula = [];
28
+ columnNames = Array.isArray(columnNames) ? columnNames : [columnNames];
29
+ for (let column of Object.values(table.schema)) {
30
+ // not a static formula, or doesn't contain a relationship
31
+ if (!isStaticFormula(column)) {
32
+ continue;
33
+ }
34
+ if (!doesContainStrings(column.formula, columnNames)) {
35
+ continue;
36
+ }
37
+ formula.push(column.name);
38
+ }
39
+ return formula;
40
+ }
41
+ /**
42
+ * This functions checks for when a related table, column or related column is deleted, if any
43
+ * tables need to have the formula column removed.
44
+ */
45
+ function checkIfFormulaNeedsCleared(appId, table, { oldTable, deletion }) {
46
+ return __awaiter(this, void 0, void 0, function* () {
47
+ const db = new CouchDB(appId);
48
+ // start by retrieving all tables, remove the current table from the list
49
+ const tables = (yield getAllInternalTables(appId)).filter(tbl => tbl._id !== table._id);
50
+ const schemaToUse = oldTable ? oldTable.schema : table.schema;
51
+ let removedColumns = Object.values(schemaToUse).filter(column => deletion || !table.schema[column.name]);
52
+ // remove any formula columns that used related columns
53
+ for (let removed of removedColumns) {
54
+ let tableToUse = table;
55
+ // if relationship, get the related table
56
+ if (removed.type === FieldTypes.LINK) {
57
+ tableToUse = tables.find(table => table._id === removed.tableId);
58
+ }
59
+ const columnsToDelete = getFormulaThatUseColumn(tableToUse, removed.name);
60
+ if (columnsToDelete.length > 0) {
61
+ yield clearColumns(db, table, columnsToDelete);
62
+ }
63
+ // need a special case, where a column has been removed from this table, but was used
64
+ // in a different, related tables formula
65
+ if (!table.relatedFormula) {
66
+ continue;
67
+ }
68
+ for (let relatedTableId of table.relatedFormula) {
69
+ const relatedColumns = Object.values(table.schema).filter(column => column.tableId === relatedTableId);
70
+ const relatedTable = tables.find(table => table._id === relatedTableId);
71
+ // look to see if the column was used in a relationship formula,
72
+ // relationships won't be used for this
73
+ if (relatedTable && relatedColumns && removed.type !== FieldTypes.LINK) {
74
+ let relatedFormulaToRemove = [];
75
+ for (let column of relatedColumns) {
76
+ relatedFormulaToRemove = relatedFormulaToRemove.concat(getFormulaThatUseColumn(relatedTable, [
77
+ column.fieldName,
78
+ removed.name,
79
+ ]));
80
+ }
81
+ if (relatedFormulaToRemove.length > 0) {
82
+ yield clearColumns(db, relatedTable, uniq(relatedFormulaToRemove));
83
+ }
84
+ }
85
+ }
86
+ }
87
+ });
88
+ }
89
+ /**
90
+ * This function adds a note to related tables that they are
91
+ * used in a static formula - so that the link controller
92
+ * can manage hydrating related rows formula fields. This is
93
+ * specifically only for static formula.
94
+ */
95
+ function updateRelatedFormulaLinksOnTables(appId, table, { deletion } = { deletion: false }) {
96
+ return __awaiter(this, void 0, void 0, function* () {
97
+ const db = new CouchDB(appId);
98
+ // start by retrieving all tables, remove the current table from the list
99
+ const tables = (yield getAllInternalTables(appId)).filter(tbl => tbl._id !== table._id);
100
+ // clone the tables, so we can compare at end
101
+ const initialTables = cloneDeep(tables);
102
+ // first find the related column names
103
+ const relatedColumns = Object.values(table.schema).filter(col => col.type === FieldTypes.LINK);
104
+ // we start by removing the formula field from all tables
105
+ for (let otherTable of tables) {
106
+ if (!otherTable.relatedFormula) {
107
+ continue;
108
+ }
109
+ const index = otherTable.relatedFormula.indexOf(table._id);
110
+ if (index !== -1) {
111
+ otherTable.relatedFormula.splice(index, 1);
112
+ }
113
+ }
114
+ // if deleting, just remove the table IDs, don't try add
115
+ if (!deletion) {
116
+ for (let relatedCol of relatedColumns) {
117
+ let columns = getFormulaThatUseColumn(table, relatedCol.name);
118
+ if (!columns || columns.length === 0) {
119
+ continue;
120
+ }
121
+ const relatedTable = tables.find(related => related._id === relatedCol.tableId);
122
+ // check if the table is already in the list of related formula, if it isn't, then add it
123
+ if (relatedTable &&
124
+ (!relatedTable.relatedFormula ||
125
+ !relatedTable.relatedFormula.includes(table._id))) {
126
+ relatedTable.relatedFormula = relatedTable.relatedFormula
127
+ ? [...relatedTable.relatedFormula, table._id]
128
+ : [table._id];
129
+ }
130
+ }
131
+ }
132
+ // now we just need to compare all the tables and see if any need saved
133
+ for (let initial of initialTables) {
134
+ const found = tables.find(tbl => initial._id === tbl._id);
135
+ if (found && !isEqual(initial, found)) {
136
+ yield db.put(found);
137
+ }
138
+ }
139
+ });
140
+ }
141
+ function checkIfFormulaUpdated(appId, table, { oldTable }) {
142
+ return __awaiter(this, void 0, void 0, function* () {
143
+ // look to see if any formula values have changed
144
+ const shouldUpdate = Object.values(table.schema).find(column => isStaticFormula(column) &&
145
+ (!oldTable ||
146
+ !oldTable.schema[column.name] ||
147
+ !isEqual(oldTable.schema[column.name], column)));
148
+ // if a static formula column has updated, then need to run the update
149
+ if (shouldUpdate != null) {
150
+ yield updateAllFormulasInTable(appId, table);
151
+ }
152
+ });
153
+ }
154
+ exports.runStaticFormulaChecks = (appId, table, { oldTable, deletion }) => __awaiter(void 0, void 0, void 0, function* () {
155
+ yield updateRelatedFormulaLinksOnTables(appId, table, { deletion });
156
+ yield checkIfFormulaNeedsCleared(appId, table, { oldTable, deletion });
157
+ if (!deletion) {
158
+ yield checkIfFormulaUpdated(appId, table, { oldTable });
159
+ }
160
+ });
@@ -13,8 +13,8 @@ const internal = require("./internal");
13
13
  const external = require("./external");
14
14
  const csvParser = require("../../../utilities/csvParser");
15
15
  const { isExternalTable, isSQL } = require("../../../integrations/utils");
16
- const { getTableParams, getDatasourceParams, BudibaseInternalDB, } = require("../../../db/utils");
17
- const { getTable } = require("./utils");
16
+ const { getDatasourceParams } = require("../../../db/utils");
17
+ const { getTable, getAllInternalTables } = require("./utils");
18
18
  function pickApi({ tableId, table }) {
19
19
  if (table && !tableId) {
20
20
  tableId = table._id;
@@ -31,10 +31,7 @@ function pickApi({ tableId, table }) {
31
31
  exports.fetch = function (ctx) {
32
32
  return __awaiter(this, void 0, void 0, function* () {
33
33
  const db = new CouchDB(ctx.appId);
34
- const internalTables = yield db.allDocs(getTableParams(null, {
35
- include_docs: true,
36
- }));
37
- const internal = internalTables.rows.map(tableDoc => (Object.assign(Object.assign({}, tableDoc.doc), { type: "internal", sourceId: BudibaseInternalDB._id })));
34
+ const internal = yield getAllInternalTables(ctx.appId);
38
35
  const externalTables = yield db.allDocs(getDatasourceParams("plus", {
39
36
  include_docs: true,
40
37
  }));
@@ -25,6 +25,8 @@ const { getRowParams, generateTableID } = require("../../../db/utils");
25
25
  const { FieldTypes } = require("../../../constants");
26
26
  const { TableSaveFunctions, hasTypeChanged, getTable, handleDataImport, } = require("./utils");
27
27
  const usageQuota = require("../../../utilities/usageQuota");
28
+ const { cleanupAttachments } = require("../../../utilities/rowProcessor");
29
+ const { runStaticFormulaChecks } = require("./bulkFormula");
28
30
  exports.save = function (ctx) {
29
31
  return __awaiter(this, void 0, void 0, function* () {
30
32
  const appId = ctx.appId;
@@ -106,6 +108,8 @@ exports.save = function (ctx) {
106
108
  const result = yield db.put(tableToSave);
107
109
  tableToSave._rev = result.rev;
108
110
  tableToSave = yield tableSaveFunctions.after(tableToSave);
111
+ // has to run after, make sure it has _id
112
+ yield runStaticFormulaChecks(appId, tableToSave, { oldTable });
109
113
  return tableToSave;
110
114
  });
111
115
  };
@@ -134,6 +138,9 @@ exports.destroy = function (ctx) {
134
138
  if (existingIndex) {
135
139
  yield db.deleteIndex(existingIndex);
136
140
  }
141
+ // has to run after, make sure it has _id
142
+ yield runStaticFormulaChecks(appId, tableToDelete, { deletion: true });
143
+ yield cleanupAttachments(appId, tableToDelete, { rows });
137
144
  return tableToDelete;
138
145
  });
139
146
  };