@budibase/server 2.5.9 → 2.5.10-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 (198) hide show
  1. package/builder/assets/index.24635afb.js +1794 -0
  2. package/builder/assets/index.4eae16b2.css +6 -0
  3. package/builder/index.html +2 -2
  4. package/dist/api/controllers/application.js +3 -4
  5. package/dist/api/controllers/automation.js +13 -7
  6. package/dist/api/controllers/datasource.js +1 -1
  7. package/dist/api/controllers/dev.js +1 -1
  8. package/dist/api/controllers/ops.js +40 -0
  9. package/dist/api/controllers/plugin/index.js +6 -37
  10. package/dist/api/controllers/query/index.js +2 -2
  11. package/dist/api/controllers/row/ExternalRequest.js +21 -14
  12. package/dist/api/controllers/row/internal.js +5 -2
  13. package/dist/api/controllers/row/utils.js +2 -2
  14. package/dist/api/controllers/table/index.js +2 -2
  15. package/dist/api/controllers/table/utils.js +9 -3
  16. package/dist/api/controllers/user.js +1 -83
  17. package/dist/api/controllers/view/exporters.js +3 -1
  18. package/dist/api/index.js +1 -2
  19. package/dist/api/routes/index.js +2 -2
  20. package/dist/api/routes/{cloud.js → ops.js} +19 -6
  21. package/dist/api/routes/user.js +0 -1
  22. package/dist/app.js +4 -13
  23. package/dist/automations/actions.js +32 -6
  24. package/dist/automations/index.js +3 -2
  25. package/dist/automations/steps/bash.js +6 -6
  26. package/dist/automations/steps/createRow.js +11 -11
  27. package/dist/automations/steps/delay.js +3 -3
  28. package/dist/automations/steps/deleteRow.js +8 -8
  29. package/dist/automations/steps/discord.js +8 -8
  30. package/dist/automations/steps/executeQuery.js +9 -9
  31. package/dist/automations/steps/executeScript.js +6 -6
  32. package/dist/automations/steps/filter.js +6 -6
  33. package/dist/automations/steps/integromat.js +10 -10
  34. package/dist/automations/steps/loop.js +9 -9
  35. package/dist/automations/steps/outgoingWebhook.js +10 -10
  36. package/dist/automations/steps/queryRows.js +14 -14
  37. package/dist/automations/steps/sendSmtpEmail.js +9 -9
  38. package/dist/automations/steps/serverLog.js +4 -4
  39. package/dist/automations/steps/slack.js +6 -6
  40. package/dist/automations/steps/updateRow.js +11 -11
  41. package/dist/automations/steps/zapier.js +9 -9
  42. package/dist/automations/triggerInfo/app.js +5 -5
  43. package/dist/automations/triggerInfo/cron.js +4 -4
  44. package/dist/automations/triggerInfo/rowDeleted.js +5 -5
  45. package/dist/automations/triggerInfo/rowSaved.js +7 -7
  46. package/dist/automations/triggerInfo/rowUpdated.js +7 -7
  47. package/dist/automations/triggerInfo/webhook.js +6 -6
  48. package/dist/db/utils.js +3 -2
  49. package/dist/environment.js +0 -1
  50. package/dist/events/docUpdates/index.js +17 -0
  51. package/dist/events/docUpdates/processors.js +18 -0
  52. package/dist/events/docUpdates/syncUsers.js +49 -0
  53. package/dist/events/index.js +3 -0
  54. package/dist/integrations/base/sqlTable.js +9 -2
  55. package/dist/integrations/index.js +3 -3
  56. package/dist/integrations/microsoftSqlServer.js +5 -2
  57. package/dist/integrations/mysql.js +5 -3
  58. package/dist/integrations/postgres.js +7 -5
  59. package/dist/integrations/redis.js +7 -0
  60. package/dist/integrations/rest.js +4 -0
  61. package/dist/migrations/functions/syncQuotas.js +2 -0
  62. package/dist/migrations/functions/usageQuotas/syncApps.js +1 -2
  63. package/dist/migrations/functions/usageQuotas/syncRows.js +1 -2
  64. package/dist/migrations/functions/usageQuotas/syncUsers.js +21 -0
  65. package/dist/sdk/app/applications/sync.js +117 -23
  66. package/dist/sdk/app/backups/exports.js +14 -38
  67. package/dist/sdk/index.js +2 -0
  68. package/dist/sdk/plugins/index.js +27 -0
  69. package/dist/sdk/plugins/plugins.js +53 -0
  70. package/dist/sdk/users/utils.js +21 -4
  71. package/dist/startup.js +31 -28
  72. package/dist/threads/automation.js +16 -5
  73. package/dist/tsconfig.build.tsbuildinfo +1 -1
  74. package/dist/utilities/csv.js +33 -0
  75. package/dist/utilities/fileSystem/plugin.js +33 -23
  76. package/dist/utilities/global.js +17 -12
  77. package/dist/utilities/rowProcessor/utils.js +4 -5
  78. package/dist/utilities/schema.js +5 -1
  79. package/dist/watch.js +2 -2
  80. package/dist/websockets/client.js +14 -0
  81. package/dist/websockets/grid.js +60 -0
  82. package/dist/websockets/index.js +17 -0
  83. package/dist/websockets/websocket.js +78 -0
  84. package/package.json +16 -16
  85. package/scripts/dev/manage.js +2 -0
  86. package/scripts/integrations/mssql/data/entrypoint.sh +1 -0
  87. package/scripts/integrations/mssql/data/setup.sql +17 -17
  88. package/scripts/integrations/mysql/init.sql +1 -1
  89. package/scripts/integrations/postgres/init.sql +1 -0
  90. package/src/api/controllers/application.ts +4 -4
  91. package/src/api/controllers/automation.ts +12 -6
  92. package/src/api/controllers/datasource.ts +15 -5
  93. package/src/api/controllers/dev.ts +2 -2
  94. package/src/api/controllers/ops.ts +32 -0
  95. package/src/api/controllers/plugin/index.ts +8 -45
  96. package/src/api/controllers/query/index.ts +2 -2
  97. package/src/api/controllers/row/ExternalRequest.ts +21 -12
  98. package/src/api/controllers/row/internal.ts +13 -11
  99. package/src/api/controllers/row/utils.ts +4 -4
  100. package/src/api/controllers/table/index.ts +2 -2
  101. package/src/api/controllers/table/utils.ts +10 -3
  102. package/src/api/controllers/user.ts +10 -96
  103. package/src/api/controllers/view/exporters.ts +3 -1
  104. package/src/api/index.ts +2 -4
  105. package/src/api/routes/index.ts +2 -2
  106. package/src/api/routes/ops.ts +30 -0
  107. package/src/api/routes/tests/automation.spec.js +7 -4
  108. package/src/api/routes/tests/user.spec.js +48 -37
  109. package/src/api/routes/user.ts +0 -5
  110. package/src/app.ts +4 -15
  111. package/src/automations/actions.ts +56 -24
  112. package/src/automations/index.ts +1 -1
  113. package/src/automations/steps/bash.ts +10 -7
  114. package/src/automations/steps/createRow.ts +15 -12
  115. package/src/automations/steps/delay.ts +6 -4
  116. package/src/automations/steps/deleteRow.ts +12 -9
  117. package/src/automations/steps/discord.ts +10 -8
  118. package/src/automations/steps/executeQuery.ts +13 -10
  119. package/src/automations/steps/executeScript.ts +10 -7
  120. package/src/automations/steps/filter.ts +8 -6
  121. package/src/automations/steps/integromat.ts +12 -10
  122. package/src/automations/steps/loop.ts +16 -10
  123. package/src/automations/steps/outgoingWebhook.ts +14 -11
  124. package/src/automations/steps/queryRows.ts +18 -15
  125. package/src/automations/steps/sendSmtpEmail.ts +11 -9
  126. package/src/automations/steps/serverLog.ts +6 -4
  127. package/src/automations/steps/slack.ts +8 -6
  128. package/src/automations/steps/updateRow.ts +15 -12
  129. package/src/automations/steps/zapier.ts +11 -9
  130. package/src/automations/tests/utilities/index.ts +2 -2
  131. package/src/automations/triggerInfo/app.ts +8 -5
  132. package/src/automations/triggerInfo/cron.ts +7 -4
  133. package/src/automations/triggerInfo/rowDeleted.ts +8 -5
  134. package/src/automations/triggerInfo/rowSaved.ts +10 -7
  135. package/src/automations/triggerInfo/rowUpdated.ts +10 -7
  136. package/src/automations/triggerInfo/webhook.ts +9 -6
  137. package/src/db/utils.ts +1 -0
  138. package/src/environment.ts +0 -1
  139. package/src/events/docUpdates/index.ts +1 -0
  140. package/src/events/docUpdates/processors.ts +14 -0
  141. package/src/events/docUpdates/syncUsers.ts +35 -0
  142. package/src/events/index.ts +1 -0
  143. package/src/integration-test/postgres.spec.ts +3 -1
  144. package/src/integrations/base/sqlTable.ts +9 -2
  145. package/src/integrations/index.ts +3 -3
  146. package/src/integrations/microsoftSqlServer.ts +5 -2
  147. package/src/integrations/mysql.ts +5 -3
  148. package/src/integrations/postgres.ts +7 -5
  149. package/src/integrations/redis.ts +8 -0
  150. package/src/integrations/rest.ts +3 -0
  151. package/src/migrations/functions/syncQuotas.ts +2 -0
  152. package/src/migrations/functions/usageQuotas/syncApps.ts +2 -3
  153. package/src/migrations/functions/usageQuotas/syncRows.ts +2 -3
  154. package/src/migrations/functions/usageQuotas/syncUsers.ts +9 -0
  155. package/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +2 -2
  156. package/src/migrations/functions/usageQuotas/tests/syncUsers.spec.ts +26 -0
  157. package/src/migrations/index.ts +1 -0
  158. package/src/sdk/app/applications/sync.ts +129 -22
  159. package/src/sdk/app/applications/tests/sync.spec.ts +137 -0
  160. package/src/sdk/app/backups/exports.ts +17 -41
  161. package/src/sdk/index.ts +2 -0
  162. package/src/sdk/plugins/index.ts +5 -0
  163. package/src/sdk/plugins/plugins.ts +41 -0
  164. package/src/sdk/users/tests/utils.spec.ts +1 -32
  165. package/src/sdk/users/utils.ts +23 -5
  166. package/src/startup.ts +36 -34
  167. package/src/tests/jestEnv.ts +0 -1
  168. package/src/tests/jestSetup.ts +0 -1
  169. package/src/tests/utilities/TestConfiguration.ts +28 -0
  170. package/src/tests/utilities/structures.ts +25 -17
  171. package/src/threads/automation.ts +18 -6
  172. package/src/utilities/csv.ts +22 -0
  173. package/src/utilities/fileSystem/plugin.ts +13 -4
  174. package/src/utilities/global.ts +21 -16
  175. package/src/utilities/rowProcessor/utils.ts +9 -10
  176. package/src/utilities/schema.ts +8 -0
  177. package/src/utilities/tests/csv.spec.ts +33 -0
  178. package/src/watch.ts +2 -2
  179. package/src/websockets/client.ts +11 -0
  180. package/src/websockets/grid.ts +55 -0
  181. package/src/websockets/index.ts +14 -0
  182. package/src/websockets/websocket.ts +83 -0
  183. package/tsconfig.build.json +3 -5
  184. package/tsconfig.json +2 -1
  185. package/builder/assets/index.0b358332.js +0 -1817
  186. package/builder/assets/index.7f9a008b.css +0 -6
  187. package/dist/api/controllers/cloud.js +0 -130
  188. package/dist/elasticApm.js +0 -14
  189. package/dist/package.json +0 -180
  190. package/dist/websocket.js +0 -22
  191. package/scripts/likeCypress.ts +0 -35
  192. package/src/api/controllers/cloud.ts +0 -119
  193. package/src/api/routes/cloud.ts +0 -18
  194. package/src/api/routes/tests/cloud.spec.ts +0 -54
  195. package/src/elasticApm.ts +0 -10
  196. package/src/migrations/functions/tests/syncQuotas.spec.js +0 -26
  197. package/src/tests/logging.ts +0 -34
  198. package/src/websocket.ts +0 -26
@@ -1,5 +1,4 @@
1
1
  import env from "../../environment"
2
- import packageJson from "../../../package.json"
3
2
  import {
4
3
  createLinkView,
5
4
  createRoutingView,
@@ -24,6 +23,7 @@ import {
24
23
  migrations,
25
24
  objectStore,
26
25
  ErrorCode,
26
+ env as envCore,
27
27
  } from "@budibase/backend-core"
28
28
  import { USERS_TABLE_SCHEMA } from "../../constants"
29
29
  import { buildDefaultDocs } from "../../db/defaultData/datasource_bb_default"
@@ -223,7 +223,7 @@ export async function fetchAppPackage(ctx: UserCtx) {
223
223
  )
224
224
 
225
225
  ctx.body = {
226
- application,
226
+ application: { ...application, upgradableVersion: envCore.VERSION },
227
227
  screens,
228
228
  layouts,
229
229
  clientLibPath,
@@ -264,7 +264,7 @@ async function performAppCreate(ctx: UserCtx) {
264
264
  _rev: undefined,
265
265
  appId,
266
266
  type: "app",
267
- version: packageJson.version,
267
+ version: envCore.VERSION,
268
268
  componentLibraries: ["@budibase/standard-components"],
269
269
  name: name,
270
270
  url: url,
@@ -433,7 +433,7 @@ export async function updateClient(ctx: UserCtx) {
433
433
  }
434
434
 
435
435
  // Update versions in app package
436
- const updatedToVersion = packageJson.version
436
+ const updatedToVersion = envCore.VERSION
437
437
  const appPackageUpdates = {
438
438
  version: updatedToVersion,
439
439
  revertableVersion: currentVersion,
@@ -16,9 +16,15 @@ import { setTestFlag, clearTestFlag } from "../../utilities/redis"
16
16
  import { context, cache, events } from "@budibase/backend-core"
17
17
  import { automations } from "@budibase/pro"
18
18
  import { Automation, BBContext } from "@budibase/types"
19
+ import { getActionDefinitions as actionDefs } from "../../automations/actions"
19
20
 
20
- const ACTION_DEFS = removeDeprecated(actions.ACTION_DEFINITIONS)
21
- const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
21
+ async function getActionDefinitions() {
22
+ return removeDeprecated(await actionDefs())
23
+ }
24
+
25
+ function getTriggerDefinitions() {
26
+ return removeDeprecated(triggers.TRIGGER_DEFINITIONS)
27
+ }
22
28
 
23
29
  /*************************
24
30
  * *
@@ -228,17 +234,17 @@ export async function clearLogError(ctx: BBContext) {
228
234
  }
229
235
 
230
236
  export async function getActionList(ctx: BBContext) {
231
- ctx.body = ACTION_DEFS
237
+ ctx.body = await getActionDefinitions()
232
238
  }
233
239
 
234
240
  export async function getTriggerList(ctx: BBContext) {
235
- ctx.body = TRIGGER_DEFS
241
+ ctx.body = getTriggerDefinitions()
236
242
  }
237
243
 
238
244
  export async function getDefinitionList(ctx: BBContext) {
239
245
  ctx.body = {
240
- trigger: TRIGGER_DEFS,
241
- action: ACTION_DEFS,
246
+ trigger: getTriggerDefinitions(),
247
+ action: await getActionDefinitions(),
242
248
  }
243
249
  }
244
250
 
@@ -12,7 +12,15 @@ import { getIntegration } from "../../integrations"
12
12
  import { getDatasourceAndQuery } from "./row/utils"
13
13
  import { invalidateDynamicVariables } from "../../threads/utils"
14
14
  import { db as dbCore, context, events } from "@budibase/backend-core"
15
- import { UserCtx, Datasource, Row } from "@budibase/types"
15
+ import {
16
+ UserCtx,
17
+ Datasource,
18
+ Row,
19
+ CreateDatasourceResponse,
20
+ UpdateDatasourceResponse,
21
+ UpdateDatasourceRequest,
22
+ CreateDatasourceRequest,
23
+ } from "@budibase/types"
16
24
  import sdk from "../../sdk"
17
25
 
18
26
  export async function fetch(ctx: UserCtx) {
@@ -146,7 +154,7 @@ async function invalidateVariables(
146
154
  await invalidateDynamicVariables(toInvalidate)
147
155
  }
148
156
 
149
- export async function update(ctx: UserCtx) {
157
+ export async function update(ctx: UserCtx<any, UpdateDatasourceResponse>) {
150
158
  const db = context.getAppDB()
151
159
  const datasourceId = ctx.params.datasourceId
152
160
  let datasource = await sdk.datasources.get(datasourceId)
@@ -187,15 +195,17 @@ export async function update(ctx: UserCtx) {
187
195
  }
188
196
  }
189
197
 
190
- export async function save(ctx: UserCtx) {
198
+ export async function save(
199
+ ctx: UserCtx<CreateDatasourceRequest, CreateDatasourceResponse>
200
+ ) {
191
201
  const db = context.getAppDB()
192
202
  const plus = ctx.request.body.datasource.plus
193
203
  const fetchSchema = ctx.request.body.fetchSchema
194
204
 
195
205
  const datasource = {
196
206
  _id: generateDatasourceID({ plus }),
197
- type: plus ? DocumentType.DATASOURCE_PLUS : DocumentType.DATASOURCE,
198
207
  ...ctx.request.body.datasource,
208
+ type: plus ? DocumentType.DATASOURCE_PLUS : DocumentType.DATASOURCE,
199
209
  }
200
210
 
201
211
  let schemaError = null
@@ -218,7 +228,7 @@ export async function save(ctx: UserCtx) {
218
228
  }
219
229
  }
220
230
 
221
- const response: any = {
231
+ const response: CreateDatasourceResponse = {
222
232
  datasource: await sdk.datasources.removeSecretSingle(datasource),
223
233
  }
224
234
  if (schemaError) {
@@ -4,7 +4,7 @@ import { checkSlashesInUrl } from "../../utilities"
4
4
  import { request } from "../../utilities/workerRequests"
5
5
  import { clearLock as redisClearLock } from "../../utilities/redis"
6
6
  import { DocumentType } from "../../db/utils"
7
- import { context } from "@budibase/backend-core"
7
+ import { context, env as envCore } from "@budibase/backend-core"
8
8
  import { events, db as dbCore, cache } from "@budibase/backend-core"
9
9
 
10
10
  async function redirect(ctx: any, method: string, path: string = "global") {
@@ -121,7 +121,7 @@ export async function revert(ctx: any) {
121
121
  }
122
122
 
123
123
  export async function getBudibaseVersion(ctx: any) {
124
- const version = require("../../../package.json").version
124
+ const version = envCore.VERSION
125
125
  ctx.body = {
126
126
  version,
127
127
  }
@@ -0,0 +1,32 @@
1
+ import { Ctx } from "@budibase/types"
2
+ import { logging } from "@budibase/backend-core"
3
+
4
+ interface LogRequest {
5
+ message: string
6
+ data?: any
7
+ }
8
+
9
+ interface ErrorRequest {
10
+ message: string
11
+ }
12
+
13
+ export async function log(ctx: Ctx<LogRequest>) {
14
+ const body = ctx.request.body
15
+ console.trace(body.message, body.data)
16
+ console.debug(body.message, body.data)
17
+ console.info(body.message, body.data)
18
+ console.warn(body.message, body.data)
19
+ console.error(body.message, body.data)
20
+ ctx.status = 204
21
+ }
22
+
23
+ export async function alert(ctx: Ctx<ErrorRequest>) {
24
+ const body = ctx.request.body
25
+ logging.logAlert(body.message, new Error(body.message))
26
+ ctx.status = 204
27
+ }
28
+
29
+ export async function error(ctx: Ctx<ErrorRequest>) {
30
+ const body = ctx.request.body
31
+ throw new Error(body.message)
32
+ }
@@ -1,31 +1,11 @@
1
- import { npmUpload, urlUpload, githubUpload, fileUpload } from "./uploaders"
2
- import {
3
- plugins as pluginCore,
4
- db as dbCore,
5
- tenancy,
6
- objectStore,
7
- } from "@budibase/backend-core"
8
- import { PluginType, FileType, PluginSource, Plugin } from "@budibase/types"
1
+ import { npmUpload, urlUpload, githubUpload } from "./uploaders"
2
+ import { plugins as pluginCore } from "@budibase/backend-core"
3
+ import { PluginType, FileType, PluginSource } from "@budibase/types"
9
4
  import env from "../../../environment"
10
- import { ClientAppSocket } from "../../../websocket"
5
+ import { clientAppSocket } from "../../../websockets"
6
+ import sdk from "../../../sdk"
11
7
  import { sdk as pro } from "@budibase/pro"
12
8
 
13
- export async function getPlugins(type?: PluginType) {
14
- const db = tenancy.getGlobalDB()
15
- const response = await db.allDocs(
16
- dbCore.getPluginParams(null, {
17
- include_docs: true,
18
- })
19
- )
20
- let plugins = response.rows.map((row: any) => row.doc) as Plugin[]
21
- plugins = objectStore.enrichPluginURLs(plugins)
22
- if (type) {
23
- return plugins.filter((plugin: Plugin) => plugin.schema?.type === type)
24
- } else {
25
- return plugins
26
- }
27
- }
28
-
29
9
  export async function upload(ctx: any) {
30
10
  const plugins: FileType[] =
31
11
  ctx.request.files.file.length > 1
@@ -35,7 +15,7 @@ export async function upload(ctx: any) {
35
15
  let docs = []
36
16
  // can do single or multiple plugins
37
17
  for (let plugin of plugins) {
38
- const doc = await processUploadedPlugin(plugin, PluginSource.FILE)
18
+ const doc = await sdk.plugins.processUploaded(plugin, PluginSource.FILE)
39
19
  docs.push(doc)
40
20
  }
41
21
  ctx.body = {
@@ -91,7 +71,7 @@ export async function create(ctx: any) {
91
71
 
92
72
  const doc = await pro.plugins.storePlugin(metadata, directory, source)
93
73
 
94
- ClientAppSocket.emit("plugins-update", { name, hash: doc.hash })
74
+ clientAppSocket.emit("plugins-update", { name, hash: doc.hash })
95
75
  ctx.body = {
96
76
  message: "Plugin uploaded successfully",
97
77
  plugins: [doc],
@@ -105,7 +85,7 @@ export async function create(ctx: any) {
105
85
  }
106
86
 
107
87
  export async function fetch(ctx: any) {
108
- ctx.body = await getPlugins()
88
+ ctx.body = await sdk.plugins.fetch()
109
89
  }
110
90
 
111
91
  export async function destroy(ctx: any) {
@@ -119,20 +99,3 @@ export async function destroy(ctx: any) {
119
99
  ctx.throw(400, err.message)
120
100
  }
121
101
  }
122
-
123
- export async function processUploadedPlugin(
124
- plugin: FileType,
125
- source?: PluginSource
126
- ) {
127
- const { metadata, directory } = await fileUpload(plugin)
128
- pluginCore.validate(metadata?.schema)
129
-
130
- // Only allow components in cloud
131
- if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) {
132
- throw new Error("Only component plugins are supported outside of self-host")
133
- }
134
-
135
- const doc = await pro.plugins.storePlugin(metadata, directory, source)
136
- ClientAppSocket.emit("plugin-update", { name: doc.name, hash: doc.hash })
137
- return doc
138
- }
@@ -245,7 +245,7 @@ async function execute(
245
245
  }
246
246
  const runFn = () => Runner.run(inputs)
247
247
 
248
- const { rows, pagination, extra } = await quotas.addQuery(runFn, {
248
+ const { rows, pagination, extra, info } = await quotas.addQuery(runFn, {
249
249
  datasourceId: datasource._id,
250
250
  })
251
251
  // remove the raw from execution incase transformer being used to hide data
@@ -255,7 +255,7 @@ async function execute(
255
255
  if (opts && opts.rowsOnly) {
256
256
  ctx.body = rows
257
257
  } else {
258
- ctx.body = { data: rows, pagination, ...extra }
258
+ ctx.body = { data: rows, pagination, ...extra, ...info }
259
259
  }
260
260
  } catch (err) {
261
261
  ctx.throw(400, err)
@@ -1,31 +1,32 @@
1
1
  import {
2
+ Datasource,
3
+ FieldSchema,
4
+ FieldType,
2
5
  FilterType,
3
6
  IncludeRelationship,
4
7
  Operation,
5
8
  PaginationJson,
6
9
  RelationshipsJson,
10
+ RelationshipTypes,
11
+ Row,
7
12
  SearchFilters,
8
13
  SortJson,
9
- Datasource,
10
- FieldSchema,
11
- Row,
12
- Table,
13
- RelationshipTypes,
14
- FieldType,
15
14
  SortType,
15
+ Table,
16
16
  } from "@budibase/types"
17
17
  import {
18
+ breakExternalTableId,
18
19
  breakRowIdField,
20
+ convertRowId,
19
21
  generateRowIdField,
20
22
  isRowId,
21
- convertRowId,
23
+ isSQL,
22
24
  } from "../../../integrations/utils"
23
25
  import { getDatasourceAndQuery } from "./utils"
24
26
  import { FieldTypes } from "../../../constants"
25
- import { breakExternalTableId, isSQL } from "../../../integrations/utils"
26
27
  import { processObjectSync } from "@budibase/string-templates"
27
28
  import { cloneDeep } from "lodash/fp"
28
- import { processFormulas, processDates } from "../../../utilities/rowProcessor"
29
+ import { processDates, processFormulas } from "../../../utilities/rowProcessor"
29
30
  import { db as dbCore } from "@budibase/backend-core"
30
31
  import sdk from "../../../sdk"
31
32
 
@@ -382,10 +383,18 @@ export class ExternalRequest {
382
383
  }
383
384
  const display = linkedTable.primaryDisplay
384
385
  for (let key of Object.keys(row[relationship.column])) {
385
- const related: Row = row[relationship.column][key]
386
+ let relatedRow: Row = row[relationship.column][key]
387
+ // add this row as context for the relationship
388
+ for (let col of Object.values(linkedTable.schema)) {
389
+ if (col.type === FieldType.LINK && col.tableId === table._id) {
390
+ relatedRow[col.name] = [row]
391
+ }
392
+ }
393
+ relatedRow = processFormulas(linkedTable, relatedRow)
394
+ const relatedDisplay = display ? relatedRow[display] : undefined
386
395
  row[relationship.column][key] = {
387
- primaryDisplay: display ? related[display] : undefined,
388
- _id: related._id,
396
+ primaryDisplay: relatedDisplay || "Invalid display column",
397
+ _id: relatedRow._id,
389
398
  }
390
399
  }
391
400
  }
@@ -30,7 +30,6 @@ import { finaliseRow, updateRelatedFormula } from "./staticFormula"
30
30
  import { csv, json, jsonWithSchema, Format } from "../view/exporters"
31
31
  import { apiFileReturn } from "../../../utilities/fileSystem"
32
32
  import {
33
- Ctx,
34
33
  UserCtx,
35
34
  Database,
36
35
  LinkDocumentValue,
@@ -38,7 +37,7 @@ import {
38
37
  Table,
39
38
  } from "@budibase/types"
40
39
 
41
- const { cleanExportRows } = require("./utils")
40
+ import { cleanExportRows } from "./utils"
42
41
 
43
42
  const CALCULATION_TYPES = {
44
43
  SUM: "sum",
@@ -72,7 +71,7 @@ async function getView(db: Database, viewName: string) {
72
71
  return viewInfo
73
72
  }
74
73
 
75
- async function getRawTableData(ctx: Ctx, db: Database, tableId: string) {
74
+ async function getRawTableData(ctx: UserCtx, db: Database, tableId: string) {
76
75
  let rows
77
76
  if (tableId === InternalTables.USER_METADATA) {
78
77
  await userController.fetchMetadata(ctx)
@@ -188,7 +187,7 @@ export async function save(ctx: UserCtx) {
188
187
  })
189
188
  }
190
189
 
191
- export async function fetchView(ctx: Ctx) {
190
+ export async function fetchView(ctx: UserCtx) {
192
191
  const viewName = decodeURIComponent(ctx.params.viewName)
193
192
 
194
193
  // if this is a table view being looked for just transfer to that
@@ -255,7 +254,7 @@ export async function fetchView(ctx: Ctx) {
255
254
  return rows
256
255
  }
257
256
 
258
- export async function fetch(ctx: Ctx) {
257
+ export async function fetch(ctx: UserCtx) {
259
258
  const db = context.getAppDB()
260
259
 
261
260
  const tableId = ctx.params.tableId
@@ -264,7 +263,7 @@ export async function fetch(ctx: Ctx) {
264
263
  return outputProcessing(table, rows)
265
264
  }
266
265
 
267
- export async function find(ctx: Ctx) {
266
+ export async function find(ctx: UserCtx) {
268
267
  const db = dbCore.getDB(ctx.appId)
269
268
  const table = await db.get(ctx.params.tableId)
270
269
  let row = await utils.findRow(ctx, ctx.params.tableId, ctx.params.rowId)
@@ -272,7 +271,7 @@ export async function find(ctx: Ctx) {
272
271
  return row
273
272
  }
274
273
 
275
- export async function destroy(ctx: Ctx) {
274
+ export async function destroy(ctx: UserCtx) {
276
275
  const db = context.getAppDB()
277
276
  const { _id } = ctx.request.body
278
277
  let row = await db.get(_id)
@@ -308,7 +307,7 @@ export async function destroy(ctx: Ctx) {
308
307
  return { response, row }
309
308
  }
310
309
 
311
- export async function bulkDestroy(ctx: Ctx) {
310
+ export async function bulkDestroy(ctx: UserCtx) {
312
311
  const db = context.getAppDB()
313
312
  const tableId = ctx.params.tableId
314
313
  const table = await db.get(tableId)
@@ -347,7 +346,7 @@ export async function bulkDestroy(ctx: Ctx) {
347
346
  return { response: { ok: true }, rows: processedRows }
348
347
  }
349
348
 
350
- export async function search(ctx: Ctx) {
349
+ export async function search(ctx: UserCtx) {
351
350
  // Fetch the whole table when running in cypress, as search doesn't work
352
351
  if (!env.COUCH_DB_URL && env.isCypress()) {
353
352
  return { rows: await fetch(ctx) }
@@ -387,11 +386,14 @@ export async function search(ctx: Ctx) {
387
386
  return response
388
387
  }
389
388
 
390
- export async function exportRows(ctx: Ctx) {
389
+ export async function exportRows(ctx: UserCtx) {
391
390
  const db = context.getAppDB()
392
391
  const table = await db.get(ctx.params.tableId)
393
392
  const rowIds = ctx.request.body.rows
394
393
  let format = ctx.query.format
394
+ if (typeof format !== "string") {
395
+ ctx.throw(400, "Format parameter is not valid")
396
+ }
395
397
  const { columns, query } = ctx.request.body
396
398
 
397
399
  let result
@@ -439,7 +441,7 @@ export async function exportRows(ctx: Ctx) {
439
441
  }
440
442
  }
441
443
 
442
- export async function fetchEnrichedRow(ctx: Ctx) {
444
+ export async function fetchEnrichedRow(ctx: UserCtx) {
443
445
  const db = context.getAppDB()
444
446
  const tableId = ctx.params.tableId
445
447
  const rowId = ctx.params.rowId
@@ -5,7 +5,7 @@ import { context } from "@budibase/backend-core"
5
5
  import { makeExternalQuery } from "../../../integrations/base/query"
6
6
  import { Row, Table } from "@budibase/types"
7
7
  import { Format } from "../view/exporters"
8
- import { Ctx } from "@budibase/types"
8
+ import { UserCtx } from "@budibase/types"
9
9
  import sdk from "../../../sdk"
10
10
  const validateJs = require("validate.js")
11
11
  const { cloneDeep } = require("lodash/fp")
@@ -26,7 +26,7 @@ export async function getDatasourceAndQuery(json: any) {
26
26
  return makeExternalQuery(datasource, json)
27
27
  }
28
28
 
29
- export async function findRow(ctx: Ctx, tableId: string, rowId: string) {
29
+ export async function findRow(ctx: UserCtx, tableId: string, rowId: string) {
30
30
  const db = context.getAppDB()
31
31
  let row
32
32
  // TODO remove special user case in future
@@ -137,8 +137,8 @@ export function cleanExportRows(
137
137
  delete schema[column]
138
138
  })
139
139
 
140
- // Intended to avoid 'undefined' in export
141
140
  if (format === Format.CSV) {
141
+ // Intended to append empty values in export
142
142
  const schemaKeys = Object.keys(schema)
143
143
  for (let key of schemaKeys) {
144
144
  if (columns?.length && columns.indexOf(key) > 0) {
@@ -146,7 +146,7 @@ export function cleanExportRows(
146
146
  }
147
147
  for (let row of cleanRows) {
148
148
  if (row[key] == null) {
149
- row[key] = ""
149
+ row[key] = undefined
150
150
  }
151
151
  }
152
152
  }
@@ -10,7 +10,7 @@ import { getDatasourceParams } from "../../../db/utils"
10
10
  import { context, events } from "@budibase/backend-core"
11
11
  import { Table, UserCtx } from "@budibase/types"
12
12
  import sdk from "../../../sdk"
13
- import csv from "csvtojson"
13
+ import { jsonFromCsvString } from "../../../utilities/csv"
14
14
 
15
15
  function pickApi({ tableId, table }: { tableId?: string; table?: Table }) {
16
16
  if (table && !tableId) {
@@ -104,7 +104,7 @@ export async function bulkImport(ctx: UserCtx) {
104
104
  export async function csvToJson(ctx: UserCtx) {
105
105
  const { csvString } = ctx.request.body
106
106
 
107
- const result = await csv().fromString(csvString)
107
+ const result = await jsonFromCsvString(csvString)
108
108
 
109
109
  ctx.status = 200
110
110
  ctx.body = result
@@ -110,21 +110,28 @@ export function importToRows(
110
110
  table: Table,
111
111
  user: ContextUser | null = null
112
112
  ) {
113
+ let originalTable = table
113
114
  let finalData: any = []
114
115
  for (let i = 0; i < data.length; i++) {
115
116
  let row = data[i]
116
117
  row._id = generateRowID(table._id!)
117
118
  row.tableId = table._id
119
+
120
+ // We use a reference to table here and update it after input processing,
121
+ // so that we can auto increment auto IDs in imported data properly
118
122
  const processed = inputProcessing(user, table, row, {
119
123
  noAutoRelationships: true,
120
124
  })
121
125
  row = processed.row
122
126
  table = processed.table
123
127
 
124
- for (const [fieldName, schema] of Object.entries(table.schema)) {
125
- // check whether the options need to be updated for inclusion as part of the data import
128
+ // However here we must reference the original table, as we want to mutate
129
+ // the real schema of the table passed in, not the clone used for
130
+ // incrementing auto IDs
131
+ for (const [fieldName, schema] of Object.entries(originalTable.schema)) {
126
132
  if (
127
- schema.type === FieldTypes.OPTIONS &&
133
+ (schema.type === FieldTypes.OPTIONS ||
134
+ schema.type === FieldTypes.ARRAY) &&
128
135
  row[fieldName] &&
129
136
  (!schema.constraints!.inclusion ||
130
137
  schema.constraints!.inclusion.indexOf(row[fieldName]) === -1)