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

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 (203) hide show
  1. package/builder/assets/{index.dd9e386f.css → index.ba78c49d.css} +1 -1
  2. package/builder/assets/{index.8184eed9.js → index.ed1cf508.js} +205 -204
  3. package/builder/assets/{vendor.3bd2f661.js → vendor.d526bfe8.js} +1 -1
  4. package/builder/index.html +3 -3
  5. package/coverage/clover.xml +844 -680
  6. package/coverage/coverage-final.json +12 -10
  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 +1 -1
  10. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  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 +1 -1
  16. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +1 -1
  18. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  23. package/coverage/lcov-report/api/controllers/query/index.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/index.html +40 -25
  29. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/row/internal.js.html +60 -123
  31. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +35 -11
  32. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +551 -0
  33. package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +629 -0
  37. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/table/index.html +45 -30
  39. package/coverage/lcov-report/api/controllers/table/index.js.html +11 -53
  40. package/coverage/lcov-report/api/controllers/table/internal.js.html +25 -7
  41. package/coverage/lcov-report/api/controllers/table/utils.js.html +136 -16
  42. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  46. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  48. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  49. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  50. package/coverage/lcov-report/api/index.html +1 -1
  51. package/coverage/lcov-report/api/index.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/index.html +1 -1
  64. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  81. package/coverage/lcov-report/automations/actions.js.html +1 -1
  82. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  83. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  84. package/coverage/lcov-report/automations/index.html +1 -1
  85. package/coverage/lcov-report/automations/index.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/index.html +1 -1
  95. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  99. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  103. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  111. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  112. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  113. package/coverage/lcov-report/automations/utils.js.html +1 -1
  114. package/coverage/lcov-report/constants/index.html +5 -5
  115. package/coverage/lcov-report/constants/index.js.html +19 -4
  116. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  117. package/coverage/lcov-report/constants/screens.js.html +1 -1
  118. package/coverage/lcov-report/db/client.js.html +1 -1
  119. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  120. package/coverage/lcov-report/db/index.html +1 -1
  121. package/coverage/lcov-report/db/index.js.html +1 -1
  122. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  123. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  124. package/coverage/lcov-report/db/linkedRows/index.js.html +10 -13
  125. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  126. package/coverage/lcov-report/db/newid.js.html +1 -1
  127. package/coverage/lcov-report/db/utils.js.html +5 -5
  128. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  129. package/coverage/lcov-report/events/index.html +1 -1
  130. package/coverage/lcov-report/events/index.js.html +1 -1
  131. package/coverage/lcov-report/events/utils.js.html +1 -1
  132. package/coverage/lcov-report/index.html +44 -44
  133. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  134. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  135. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  136. package/coverage/lcov-report/middleware/authorized.js.html +1 -1
  137. package/coverage/lcov-report/middleware/builder.js.html +1 -1
  138. package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
  139. package/coverage/lcov-report/middleware/index.html +1 -1
  140. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  141. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  142. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  143. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  144. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  145. package/coverage/lcov-report/migrations/usageQuotas/index.html +1 -1
  146. package/coverage/lcov-report/migrations/usageQuotas/index.js.html +1 -1
  147. package/coverage/lcov-report/migrations/usageQuotas/syncApps.js.html +1 -1
  148. package/coverage/lcov-report/migrations/usageQuotas/syncRows.js.html +1 -1
  149. package/coverage/lcov-report/threads/automation.js.html +1 -1
  150. package/coverage/lcov-report/threads/index.html +1 -1
  151. package/coverage/lcov-report/threads/index.js.html +1 -1
  152. package/coverage/lcov-report/threads/query.js.html +1 -1
  153. package/coverage/lcov-report/threads/utils.js.html +1 -1
  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 +1 -1
  158. package/coverage/lcov-report/utilities/global.js.html +1 -1
  159. package/coverage/lcov-report/utilities/index.html +1 -1
  160. package/coverage/lcov-report/utilities/index.js.html +1 -1
  161. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
  162. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  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 +27 -27
  166. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +65 -29
  167. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +73 -25
  168. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  169. package/coverage/lcov-report/utilities/security.js.html +1 -1
  170. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  171. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  172. package/coverage/lcov-report/utilities/usageQuota/index.js.html +1 -1
  173. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  174. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  175. package/coverage/lcov-report/utilities/users.js.html +1 -1
  176. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  177. package/coverage/lcov.info +1509 -1173
  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/constants/index.js +4 -0
  186. package/dist/db/linkedRows/index.js +4 -5
  187. package/dist/package.json +4 -4
  188. package/dist/tsconfig.tsbuildinfo +1 -1
  189. package/dist/utilities/rowProcessor/index.js +18 -11
  190. package/dist/utilities/rowProcessor/utils.js +14 -4
  191. package/package.json +5 -5
  192. package/src/api/controllers/row/internal.js +29 -50
  193. package/src/api/controllers/row/internalSearch.js +12 -4
  194. package/src/api/controllers/row/staticFormula.js +157 -0
  195. package/src/api/controllers/table/bulkFormula.js +183 -0
  196. package/src/api/controllers/table/index.js +3 -17
  197. package/src/api/controllers/table/internal.js +7 -1
  198. package/src/api/controllers/table/utils.js +48 -8
  199. package/src/constants/index.js +5 -0
  200. package/src/db/linkedRows/index.js +4 -5
  201. package/src/definitions/common.ts +3 -0
  202. package/src/utilities/rowProcessor/index.js +24 -12
  203. package/src/utilities/rowProcessor/utils.js +23 -7
@@ -3,12 +3,8 @@ const internal = require("./internal")
3
3
  const external = require("./external")
4
4
  const csvParser = require("../../../utilities/csvParser")
5
5
  const { isExternalTable, isSQL } = require("../../../integrations/utils")
6
- const {
7
- getTableParams,
8
- getDatasourceParams,
9
- BudibaseInternalDB,
10
- } = require("../../../db/utils")
11
- const { getTable } = require("./utils")
6
+ const { getDatasourceParams } = require("../../../db/utils")
7
+ const { getTable, getAllInternalTables } = require("./utils")
12
8
 
13
9
  function pickApi({ tableId, table }) {
14
10
  if (table && !tableId) {
@@ -26,17 +22,7 @@ function pickApi({ tableId, table }) {
26
22
  exports.fetch = async function (ctx) {
27
23
  const db = new CouchDB(ctx.appId)
28
24
 
29
- const internalTables = await db.allDocs(
30
- getTableParams(null, {
31
- include_docs: true,
32
- })
33
- )
34
-
35
- const internal = internalTables.rows.map(tableDoc => ({
36
- ...tableDoc.doc,
37
- type: "internal",
38
- sourceId: BudibaseInternalDB._id,
39
- }))
25
+ const internal = await getAllInternalTables(ctx.appId)
40
26
 
41
27
  const externalTables = await db.allDocs(
42
28
  getDatasourceParams("plus", {
@@ -9,6 +9,8 @@ const {
9
9
  handleDataImport,
10
10
  } = require("./utils")
11
11
  const usageQuota = require("../../../utilities/usageQuota")
12
+ const { cleanupAttachments } = require("../../../utilities/rowProcessor")
13
+ const { runStaticFormulaChecks } = require("./bulkFormula")
12
14
 
13
15
  exports.save = async function (ctx) {
14
16
  const appId = ctx.appId
@@ -104,7 +106,8 @@ exports.save = async function (ctx) {
104
106
  tableToSave._rev = result.rev
105
107
 
106
108
  tableToSave = await tableSaveFunctions.after(tableToSave)
107
-
109
+ // has to run after, make sure it has _id
110
+ await runStaticFormulaChecks(appId, tableToSave, { oldTable })
108
111
  return tableToSave
109
112
  }
110
113
 
@@ -141,6 +144,9 @@ exports.destroy = async function (ctx) {
141
144
  await db.deleteIndex(existingIndex)
142
145
  }
143
146
 
147
+ // has to run after, make sure it has _id
148
+ await runStaticFormulaChecks(appId, tableToDelete, { deletion: true })
149
+ await cleanupAttachments(appId, tableToDelete, { rows })
144
150
  return tableToDelete
145
151
  }
146
152
 
@@ -4,10 +4,15 @@ const {
4
4
  getRowParams,
5
5
  generateRowID,
6
6
  InternalTables,
7
+ getTableParams,
8
+ BudibaseInternalDB,
7
9
  } = require("../../../db/utils")
8
- const { isEqual } = require("lodash/fp")
10
+ const { isEqual } = require("lodash")
9
11
  const { AutoFieldSubTypes, FieldTypes } = require("../../../constants")
10
- const { inputProcessing } = require("../../../utilities/rowProcessor")
12
+ const {
13
+ inputProcessing,
14
+ cleanupAttachments,
15
+ } = require("../../../utilities/rowProcessor")
11
16
  const {
12
17
  USERS_TABLE_SCHEMA,
13
18
  SwitchableTypes,
@@ -21,8 +26,24 @@ const {
21
26
  const { getViews, saveView } = require("../view/utils")
22
27
  const viewTemplate = require("../view/viewBuilder")
23
28
  const usageQuota = require("../../../utilities/usageQuota")
29
+ const { cloneDeep } = require("lodash/fp")
30
+
31
+ exports.clearColumns = async (appId, table, columnNames) => {
32
+ const db = new CouchDB(appId)
33
+ const rows = await db.allDocs(
34
+ getRowParams(table._id, null, {
35
+ include_docs: true,
36
+ })
37
+ )
38
+ return db.bulkDocs(
39
+ rows.rows.map(({ doc }) => {
40
+ columnNames.forEach(colName => delete doc[colName])
41
+ return doc
42
+ })
43
+ )
44
+ }
24
45
 
25
- exports.checkForColumnUpdates = async (db, oldTable, updatedTable) => {
46
+ exports.checkForColumnUpdates = async (appId, db, oldTable, updatedTable) => {
26
47
  let updatedRows = []
27
48
  const rename = updatedTable._rename
28
49
  let deletedColumns = []
@@ -39,16 +60,20 @@ exports.checkForColumnUpdates = async (db, oldTable, updatedTable) => {
39
60
  include_docs: true,
40
61
  })
41
62
  )
42
- updatedRows = rows.rows.map(({ doc }) => {
63
+ const rawRows = rows.rows.map(({ doc }) => doc)
64
+ updatedRows = rawRows.map(row => {
65
+ row = cloneDeep(row)
43
66
  if (rename) {
44
- doc[rename.updated] = doc[rename.old]
45
- delete doc[rename.old]
67
+ row[rename.updated] = row[rename.old]
68
+ delete row[rename.old]
46
69
  } else if (deletedColumns.length !== 0) {
47
- deletedColumns.forEach(colName => delete doc[colName])
70
+ deletedColumns.forEach(colName => delete row[colName])
48
71
  }
49
- return doc
72
+ return row
50
73
  })
51
74
 
75
+ // cleanup any attachments from object storage for deleted attachment columns
76
+ await cleanupAttachments(appId, updatedTable, { oldTable, rows: rawRows })
52
77
  // Update views
53
78
  await exports.checkForViewUpdates(db, updatedTable, rename, deletedColumns)
54
79
  delete updatedTable._rename
@@ -209,6 +234,7 @@ class TableSaveFunctions {
209
234
  // when confirmed valid
210
235
  async mid(table) {
211
236
  let response = await exports.checkForColumnUpdates(
237
+ this.appId,
212
238
  this.db,
213
239
  this.oldTable,
214
240
  table
@@ -234,6 +260,20 @@ class TableSaveFunctions {
234
260
  }
235
261
  }
236
262
 
263
+ exports.getAllInternalTables = async appId => {
264
+ const db = new CouchDB(appId)
265
+ const internalTables = await db.allDocs(
266
+ getTableParams(null, {
267
+ include_docs: true,
268
+ })
269
+ )
270
+ return internalTables.rows.map(tableDoc => ({
271
+ ...tableDoc.doc,
272
+ type: "internal",
273
+ sourceId: BudibaseInternalDB._id,
274
+ }))
275
+ }
276
+
237
277
  exports.getAllExternalTables = async (appId, datasourceId) => {
238
278
  const db = new CouchDB(appId)
239
279
  const datasource = await db.get(datasourceId)
@@ -61,6 +61,11 @@ exports.RelationshipTypes = {
61
61
  MANY_TO_MANY: "many-to-many",
62
62
  }
63
63
 
64
+ exports.FormulaTypes = {
65
+ STATIC: "static",
66
+ DYNAMIC: "dynamic",
67
+ }
68
+
64
69
  exports.AuthTypes = {
65
70
  APP: "app",
66
71
  BUILDER: "builder",
@@ -72,7 +72,7 @@ async function getLinksForRows(appId, rows) {
72
72
  )
73
73
  }
74
74
 
75
- async function getFullLinkedDocs(ctx, appId, links) {
75
+ async function getFullLinkedDocs(appId, links) {
76
76
  // create DBs
77
77
  const db = new CouchDB(appId)
78
78
  const linkedRowIds = links.map(link => link.id)
@@ -146,13 +146,12 @@ exports.updateLinks = async function (args) {
146
146
  /**
147
147
  * Given a table and a list of rows this will retrieve all of the attached docs and enrich them into the row.
148
148
  * This is required for formula fields, this may only be utilised internally (for now).
149
- * @param {object} ctx The request which is looking for rows.
149
+ * @param {string} appId The ID of the app which this request is in the context of.
150
150
  * @param {object} table The table from which the rows originated.
151
151
  * @param {array<object>} rows The rows which are to be enriched.
152
152
  * @return {Promise<*>} returns the rows with all of the enriched relationships on it.
153
153
  */
154
- exports.attachFullLinkedDocs = async (ctx, table, rows) => {
155
- const appId = ctx.appId
154
+ exports.attachFullLinkedDocs = async (appId, table, rows) => {
156
155
  const linkedTableIds = getLinkedTableIDs(table)
157
156
  if (linkedTableIds.length === 0) {
158
157
  return rows
@@ -166,7 +165,7 @@ exports.attachFullLinkedDocs = async (ctx, table, rows) => {
166
165
  // clear any existing links that could be dupe'd
167
166
  rows = clearRelationshipFields(table, rows)
168
167
  // now get the docs and combine into the rows
169
- let linked = await getFullLinkedDocs(ctx, appId, links)
168
+ let linked = await getFullLinkedDocs(appId, links)
170
169
  const linkedTables = []
171
170
  for (let row of rows) {
172
171
  for (let link of links.filter(link => link.thisId === row._id)) {
@@ -17,6 +17,8 @@ export interface FieldSchema {
17
17
  autocolumn?: boolean
18
18
  throughFrom?: string
19
19
  throughTo?: string
20
+ formula?: string
21
+ formulaType?: string
20
22
  main?: boolean
21
23
  meta?: {
22
24
  toTable: string
@@ -46,6 +48,7 @@ export interface Table extends Base {
46
48
  schema: TableSchema
47
49
  primaryDisplay?: string
48
50
  sourceId?: string
51
+ relatedFormula?: string[]
49
52
  constrained?: string[]
50
53
  }
51
54
 
@@ -180,6 +180,8 @@ function processAutoColumn(
180
180
  }
181
181
  exports.processAutoColumn = processAutoColumn
182
182
 
183
+ exports.processFormulas = processFormulas
184
+
183
185
  /**
184
186
  * This will coerce a value to the correct types based on the type transform map
185
187
  * @param {object} row The value to coerce
@@ -229,11 +231,12 @@ exports.inputProcessing = (
229
231
  }
230
232
  continue
231
233
  }
232
- // specific case to delete formula values if they get saved
233
- // type coercion cannot completely remove the field, so have to do it here
234
+ // remove any formula values, they are to be generated
234
235
  if (field.type === FieldTypes.FORMULA) {
235
236
  delete clonedRow[key]
236
- } else {
237
+ }
238
+ // otherwise coerce what is there to correct types
239
+ else {
237
240
  clonedRow[key] = exports.coerce(value, field.type)
238
241
  }
239
242
  }
@@ -250,7 +253,7 @@ exports.inputProcessing = (
250
253
  /**
251
254
  * This function enriches the input rows with anything they are supposed to contain, for example
252
255
  * link records or attachment links.
253
- * @param {object} ctx the request which is looking for enriched rows.
256
+ * @param {string} appId the app in which the request is looking for enriched rows.
254
257
  * @param {object} table the table from which these rows came from originally, this is used to determine
255
258
  * the schema of the rows and then enrich.
256
259
  * @param {object[]|object} rows the rows which are to be enriched.
@@ -258,22 +261,21 @@ exports.inputProcessing = (
258
261
  * @returns {object[]|object} the enriched rows will be returned.
259
262
  */
260
263
  exports.outputProcessing = async (
261
- ctx,
264
+ { appId },
262
265
  table,
263
266
  rows,
264
267
  opts = { squash: true }
265
268
  ) => {
266
- const appId = ctx.appId
267
269
  let wasArray = true
268
270
  if (!(rows instanceof Array)) {
269
271
  rows = [rows]
270
272
  wasArray = false
271
273
  }
272
274
  // attach any linked row information
273
- let enriched = await linkRows.attachFullLinkedDocs(ctx, table, rows)
275
+ let enriched = await linkRows.attachFullLinkedDocs(appId, table, rows)
274
276
 
275
277
  // process formulas
276
- enriched = processFormulas(table, enriched)
278
+ enriched = processFormulas(table, enriched, { dynamic: true })
277
279
 
278
280
  // update the attachments URL depending on hosting
279
281
  for (let [property, column] of Object.entries(table.schema)) {
@@ -305,9 +307,15 @@ exports.outputProcessing = async (
305
307
  * @param {any} row optional - the row being removed.
306
308
  * @param {any} rows optional - if multiple rows being deleted can do this in bulk.
307
309
  * @param {any} oldRow optional - if updating a row this will determine the difference.
310
+ * @param {any} oldTable optional - if updating a table, can supply the old table to look for
311
+ * deleted attachment columns.
308
312
  * @return {Promise<void>} When all attachments have been removed this will return.
309
313
  */
310
- exports.cleanupAttachments = async (appId, table, { row, rows, oldRow }) => {
314
+ exports.cleanupAttachments = async (
315
+ appId,
316
+ table,
317
+ { row, rows, oldRow, oldTable }
318
+ ) => {
311
319
  if (!isProdAppID(appId)) {
312
320
  const prodAppId = getDeployedAppID(appId)
313
321
  // if prod exists, then don't allow deleting
@@ -322,12 +330,16 @@ exports.cleanupAttachments = async (appId, table, { row, rows, oldRow }) => {
322
330
  files = files.concat(row[key].map(attachment => attachment.key))
323
331
  }
324
332
  }
325
- for (let [key, schema] of Object.entries(table.schema)) {
333
+ const schemaToUse = oldTable ? oldTable.schema : table.schema
334
+ for (let [key, schema] of Object.entries(schemaToUse)) {
326
335
  if (schema.type !== FieldTypes.ATTACHMENT) {
327
336
  continue
328
337
  }
329
- // if updating, need to manage the differences
330
- if (oldRow && row) {
338
+ // old table had this column, new table doesn't - delete it
339
+ if (oldTable && !table.schema[key]) {
340
+ rows.forEach(row => addFiles(row, key))
341
+ } else if (oldRow && row) {
342
+ // if updating, need to manage the differences
331
343
  files = files.concat(getRemovedAttachmentKeys(oldRow, row, key))
332
344
  } else if (row) {
333
345
  addFiles(row, key)
@@ -1,23 +1,39 @@
1
- const { FieldTypes } = require("../../constants")
1
+ const { FieldTypes, FormulaTypes } = require("../../constants")
2
2
  const { processStringSync } = require("@budibase/string-templates")
3
3
 
4
4
  /**
5
5
  * Looks through the rows provided and finds formulas - which it then processes.
6
6
  */
7
- exports.processFormulas = (table, rows) => {
7
+ exports.processFormulas = (
8
+ table,
9
+ rows,
10
+ { dynamic, contextRows } = { dynamic: true }
11
+ ) => {
8
12
  const single = !Array.isArray(rows)
9
13
  if (single) {
10
14
  rows = [rows]
15
+ contextRows = contextRows ? [contextRows] : contextRows
11
16
  }
12
17
  for (let [column, schema] of Object.entries(table.schema)) {
13
- if (schema.type !== FieldTypes.FORMULA) {
18
+ const isStatic = schema.formulaType === FormulaTypes.STATIC
19
+ if (
20
+ schema.type !== FieldTypes.FORMULA ||
21
+ (dynamic && isStatic) ||
22
+ (!dynamic && !isStatic)
23
+ ) {
14
24
  continue
15
25
  }
16
26
  // iterate through rows and process formula
17
- rows = rows.map(row => ({
18
- ...row,
19
- [column]: processStringSync(schema.formula, row),
20
- }))
27
+ for (let i = 0; i < rows.length; i++) {
28
+ if (schema.formula) {
29
+ let row = rows[i]
30
+ let context = contextRows ? contextRows[i] : row
31
+ rows[i] = {
32
+ ...row,
33
+ [column]: processStringSync(schema.formula, context),
34
+ }
35
+ }
36
+ }
21
37
  }
22
38
  return single ? rows[0] : rows
23
39
  }