@budibase/server 1.2.42 → 1.2.45

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 (162) hide show
  1. package/builder/assets/{index.b0f613b5.js → index.0956c8bc.js} +6 -6
  2. package/builder/index.html +1 -1
  3. package/coverage/clover.xml +305 -297
  4. package/coverage/coverage-final.json +20 -20
  5. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  6. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  7. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/index.html +1 -1
  14. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  20. package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/row/index.html +19 -19
  25. package/coverage/lcov-report/api/controllers/row/internal.js.html +88 -46
  26. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +15 -15
  28. package/coverage/lcov-report/api/controllers/row/utils.js.html +13 -13
  29. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +41 -41
  32. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  34. package/coverage/lcov-report/api/controllers/table/index.js.html +17 -17
  35. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/view/exporters.js.html +2 -2
  38. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  39. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  43. package/coverage/lcov-report/api/index.html +1 -1
  44. package/coverage/lcov-report/api/index.js.html +5 -5
  45. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  46. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  47. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  48. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/index.html +1 -1
  56. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/utils/index.html +1 -1
  70. package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  73. package/coverage/lcov-report/automations/actions.js.html +1 -1
  74. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  75. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  76. package/coverage/lcov-report/automations/index.html +1 -1
  77. package/coverage/lcov-report/automations/index.js.html +1 -1
  78. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  79. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  80. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  81. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  82. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/index.html +1 -1
  85. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  95. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  96. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  97. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  98. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  104. package/coverage/lcov-report/constants/index.html +1 -1
  105. package/coverage/lcov-report/constants/index.js.html +1 -1
  106. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  107. package/coverage/lcov-report/constants/screens.js.html +1 -1
  108. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  109. package/coverage/lcov-report/db/index.html +1 -1
  110. package/coverage/lcov-report/db/index.js.html +1 -1
  111. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +11 -11
  112. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  113. package/coverage/lcov-report/db/linkedRows/index.js.html +19 -19
  114. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +7 -7
  115. package/coverage/lcov-report/db/newid.js.html +2 -2
  116. package/coverage/lcov-report/db/utils.js.html +11 -11
  117. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  118. package/coverage/lcov-report/events/index.html +1 -1
  119. package/coverage/lcov-report/events/index.js.html +1 -1
  120. package/coverage/lcov-report/events/utils.js.html +1 -1
  121. package/coverage/lcov-report/index.html +19 -19
  122. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  123. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  124. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  125. package/coverage/lcov-report/middleware/builder.js.html +12 -12
  126. package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
  127. package/coverage/lcov-report/middleware/index.html +1 -1
  128. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  129. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  130. package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
  131. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  132. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  133. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  134. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  135. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  136. package/coverage/lcov-report/utilities/global.js.html +16 -16
  137. package/coverage/lcov-report/utilities/index.html +1 -1
  138. package/coverage/lcov-report/utilities/index.js.html +1 -1
  139. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  140. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  141. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  142. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  143. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  144. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +39 -39
  145. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +10 -10
  146. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  147. package/coverage/lcov-report/utilities/security.js.html +1 -1
  148. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  149. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  150. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  151. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  152. package/coverage/lcov-report/utilities/users.js.html +1 -1
  153. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  154. package/coverage/lcov.info +533 -521
  155. package/dist/api/controllers/row/internal.js +15 -1
  156. package/dist/automations/utils.js +1 -1
  157. package/dist/package.json +7 -7
  158. package/dist/tsconfig.build.tsbuildinfo +1 -1
  159. package/package.json +8 -8
  160. package/src/api/controllers/row/internal.js +15 -1
  161. package/src/api/routes/tests/row.spec.js +149 -67
  162. package/src/automations/utils.ts +1 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/server",
3
3
  "email": "hi@budibase.com",
4
- "version": "1.2.42",
4
+ "version": "1.2.45",
5
5
  "description": "Budibase Web Server",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -77,11 +77,11 @@
77
77
  "license": "GPL-3.0",
78
78
  "dependencies": {
79
79
  "@apidevtools/swagger-parser": "10.0.3",
80
- "@budibase/backend-core": "^1.2.42",
81
- "@budibase/client": "^1.2.42",
82
- "@budibase/pro": "1.2.41",
83
- "@budibase/string-templates": "^1.2.42",
84
- "@budibase/types": "^1.2.42",
80
+ "@budibase/backend-core": "^1.2.45",
81
+ "@budibase/client": "^1.2.45",
82
+ "@budibase/pro": "1.2.44",
83
+ "@budibase/string-templates": "^1.2.45",
84
+ "@budibase/types": "^1.2.45",
85
85
  "@bull-board/api": "3.7.0",
86
86
  "@bull-board/koa": "3.9.4",
87
87
  "@elastic/elasticsearch": "7.10.0",
@@ -93,7 +93,7 @@
93
93
  "arangojs": "7.2.0",
94
94
  "aws-sdk": "2.1030.0",
95
95
  "bcryptjs": "2.4.3",
96
- "bull": "3.29.3",
96
+ "bull": "4.8.5",
97
97
  "chmodr": "1.2.0",
98
98
  "csvtojson": "2.0.10",
99
99
  "curlconverter": "3.21.0",
@@ -195,5 +195,5 @@
195
195
  "optionalDependencies": {
196
196
  "oracledb": "5.3.0"
197
197
  },
198
- "gitHead": "111226abbd5e491027931e272d2267f25057fb13"
198
+ "gitHead": "b390187ee3b142cc871552f596a7023abe69ef44"
199
199
  }
@@ -375,6 +375,7 @@ exports.exportRows = async ctx => {
375
375
  const table = await db.get(ctx.params.tableId)
376
376
  const rowIds = ctx.request.body.rows
377
377
  let format = ctx.query.format
378
+ const { columns } = ctx.request.body
378
379
  let response = (
379
380
  await db.allDocs({
380
381
  include_docs: true,
@@ -382,7 +383,20 @@ exports.exportRows = async ctx => {
382
383
  })
383
384
  ).rows.map(row => row.doc)
384
385
 
385
- let rows = await outputProcessing(table, response)
386
+ let result = await outputProcessing(table, response)
387
+ let rows = []
388
+
389
+ // Filter data to only specified columns if required
390
+ if (columns && columns.length) {
391
+ for (let i = 0; i < result.length; i++) {
392
+ rows[i] = {}
393
+ for (let column of columns) {
394
+ rows[i][column] = result[i][column]
395
+ }
396
+ }
397
+ } else {
398
+ rows = result
399
+ }
386
400
 
387
401
  let headers = Object.keys(rows[0])
388
402
  const exporter = exporters[format]
@@ -3,7 +3,12 @@ const setup = require("./utilities")
3
3
  const { basicRow } = setup.structures
4
4
  const { doInAppContext } = require("@budibase/backend-core/context")
5
5
  const { doInTenant } = require("@budibase/backend-core/tenancy")
6
- const { quotas, QuotaUsageType, StaticQuotaName, MonthlyQuotaName } = require("@budibase/pro")
6
+ const {
7
+ quotas,
8
+ QuotaUsageType,
9
+ StaticQuotaName,
10
+ MonthlyQuotaName,
11
+ } = require("@budibase/pro")
7
12
 
8
13
  describe("/rows", () => {
9
14
  let request = setup.getRequest()
@@ -23,23 +28,30 @@ describe("/rows", () => {
23
28
  await request
24
29
  .get(`/api/${table._id}/rows/${id}`)
25
30
  .set(config.defaultHeaders())
26
- .expect('Content-Type', /json/)
31
+ .expect("Content-Type", /json/)
27
32
  .expect(status)
28
33
 
29
34
  const getRowUsage = async () => {
30
- return config.doInContext(null, () => quotas.getCurrentUsageValue(QuotaUsageType.STATIC, StaticQuotaName.ROWS))
35
+ return config.doInContext(null, () =>
36
+ quotas.getCurrentUsageValue(QuotaUsageType.STATIC, StaticQuotaName.ROWS)
37
+ )
31
38
  }
32
39
 
33
40
  const getQueryUsage = async () => {
34
- return config.doInContext(null, () => quotas.getCurrentUsageValue(QuotaUsageType.MONTHLY, MonthlyQuotaName.QUERIES))
41
+ return config.doInContext(null, () =>
42
+ quotas.getCurrentUsageValue(
43
+ QuotaUsageType.MONTHLY,
44
+ MonthlyQuotaName.QUERIES
45
+ )
46
+ )
35
47
  }
36
48
 
37
- const assertRowUsage = async (expected) => {
49
+ const assertRowUsage = async expected => {
38
50
  const usage = await getRowUsage()
39
51
  expect(usage).toBe(expected)
40
52
  }
41
53
 
42
- const assertQueryUsage = async (expected) => {
54
+ const assertQueryUsage = async expected => {
43
55
  const usage = await getQueryUsage()
44
56
  expect(usage).toBe(expected)
45
57
  }
@@ -76,10 +88,12 @@ describe("/rows", () => {
76
88
  name: "Updated Name",
77
89
  })
78
90
  .set(config.defaultHeaders())
79
- .expect('Content-Type', /json/)
91
+ .expect("Content-Type", /json/)
80
92
  .expect(200)
81
93
 
82
- expect(res.res.statusMessage).toEqual(`${table.name} updated successfully.`)
94
+ expect(res.res.statusMessage).toEqual(
95
+ `${table.name} updated successfully.`
96
+ )
83
97
  expect(res.body.name).toEqual("Updated Name")
84
98
  // await assertRowUsage(rowUsage)
85
99
  // await assertQueryUsage(queryUsage + 1)
@@ -92,7 +106,7 @@ describe("/rows", () => {
92
106
  const res = await request
93
107
  .get(`/api/${table._id}/rows/${existing._id}`)
94
108
  .set(config.defaultHeaders())
95
- .expect('Content-Type', /json/)
109
+ .expect("Content-Type", /json/)
96
110
  .expect(200)
97
111
 
98
112
  expect(res.body).toEqual({
@@ -110,7 +124,7 @@ describe("/rows", () => {
110
124
  const newRow = {
111
125
  tableId: table._id,
112
126
  name: "Second Contact",
113
- status: "new"
127
+ status: "new",
114
128
  }
115
129
  await config.createRow()
116
130
  await config.createRow(newRow)
@@ -119,7 +133,7 @@ describe("/rows", () => {
119
133
  const res = await request
120
134
  .get(`/api/${table._id}/rows`)
121
135
  .set(config.defaultHeaders())
122
- .expect('Content-Type', /json/)
136
+ .expect("Content-Type", /json/)
123
137
  .expect(200)
124
138
 
125
139
  expect(res.body.length).toBe(2)
@@ -135,17 +149,36 @@ describe("/rows", () => {
135
149
  await request
136
150
  .get(`/api/${table._id}/rows/not-a-valid-id`)
137
151
  .set(config.defaultHeaders())
138
- .expect('Content-Type', /json/)
152
+ .expect("Content-Type", /json/)
139
153
  .expect(404)
140
154
  await assertQueryUsage(queryUsage) // no change
141
155
  })
142
156
 
143
157
  it("row values are coerced", async () => {
144
- const str = {type:"string", constraints: { type: "string", presence: false }}
145
- const attachment = {type:"attachment", constraints: { type: "array", presence: false }}
146
- const bool = {type:"boolean", constraints: { type: "boolean", presence: false }}
147
- const number = {type:"number", constraints: { type: "number", presence: false }}
148
- const datetime = {type:"datetime", constraints: { type: "string", presence: false, datetime: {earliest:"", latest: ""} }}
158
+ const str = {
159
+ type: "string",
160
+ constraints: { type: "string", presence: false },
161
+ }
162
+ const attachment = {
163
+ type: "attachment",
164
+ constraints: { type: "array", presence: false },
165
+ }
166
+ const bool = {
167
+ type: "boolean",
168
+ constraints: { type: "boolean", presence: false },
169
+ }
170
+ const number = {
171
+ type: "number",
172
+ constraints: { type: "number", presence: false },
173
+ }
174
+ const datetime = {
175
+ type: "datetime",
176
+ constraints: {
177
+ type: "string",
178
+ presence: false,
179
+ datetime: { earliest: "", latest: "" },
180
+ },
181
+ }
149
182
 
150
183
  table = await config.createTable({
151
184
  name: "TestTable2",
@@ -171,9 +204,9 @@ describe("/rows", () => {
171
204
  boolUndefined: bool,
172
205
  boolString: bool,
173
206
  boolBool: bool,
174
- attachmentNull : attachment,
175
- attachmentUndefined : attachment,
176
- attachmentEmpty : attachment,
207
+ attachmentNull: attachment,
208
+ attachmentUndefined: attachment,
209
+ attachmentEmpty: attachment,
177
210
  },
178
211
  })
179
212
 
@@ -198,9 +231,9 @@ describe("/rows", () => {
198
231
  boolString: "true",
199
232
  boolBool: true,
200
233
  tableId: table._id,
201
- attachmentNull : null,
202
- attachmentUndefined : undefined,
203
- attachmentEmpty : "",
234
+ attachmentNull: null,
235
+ attachmentUndefined: undefined,
236
+ attachmentEmpty: "",
204
237
  }
205
238
 
206
239
  const id = (await config.createRow(row))._id
@@ -218,7 +251,9 @@ describe("/rows", () => {
218
251
  expect(saved.datetimeEmptyString).toBe(null)
219
252
  expect(saved.datetimeNull).toBe(null)
220
253
  expect(saved.datetimeUndefined).toBe(undefined)
221
- expect(saved.datetimeString).toBe(new Date(row.datetimeString).toISOString())
254
+ expect(saved.datetimeString).toBe(
255
+ new Date(row.datetimeString).toISOString()
256
+ )
222
257
  expect(saved.datetimeDate).toBe(row.datetimeDate.toISOString())
223
258
  expect(saved.boolNull).toBe(null)
224
259
  expect(saved.boolEmpty).toBe(null)
@@ -247,10 +282,12 @@ describe("/rows", () => {
247
282
  name: "Updated Name",
248
283
  })
249
284
  .set(config.defaultHeaders())
250
- .expect('Content-Type', /json/)
285
+ .expect("Content-Type", /json/)
251
286
  .expect(200)
252
-
253
- expect(res.res.statusMessage).toEqual(`${table.name} updated successfully.`)
287
+
288
+ expect(res.res.statusMessage).toEqual(
289
+ `${table.name} updated successfully.`
290
+ )
254
291
  expect(res.body.name).toEqual("Updated Name")
255
292
  expect(res.body.description).toEqual(existing.description)
256
293
 
@@ -292,16 +329,14 @@ describe("/rows", () => {
292
329
  const res = await request
293
330
  .delete(`/api/${table._id}/rows`)
294
331
  .send({
295
- rows: [
296
- createdRow
297
- ]
332
+ rows: [createdRow],
298
333
  })
299
334
  .set(config.defaultHeaders())
300
- .expect('Content-Type', /json/)
335
+ .expect("Content-Type", /json/)
301
336
  .expect(200)
302
337
  expect(res.body[0]._id).toEqual(createdRow._id)
303
- await assertRowUsage(rowUsage -1)
304
- await assertQueryUsage(queryUsage +1)
338
+ await assertRowUsage(rowUsage - 1)
339
+ await assertQueryUsage(queryUsage + 1)
305
340
  })
306
341
  })
307
342
 
@@ -314,9 +349,9 @@ describe("/rows", () => {
314
349
  .post(`/api/${table._id}/rows/validate`)
315
350
  .send({ name: "ivan" })
316
351
  .set(config.defaultHeaders())
317
- .expect('Content-Type', /json/)
352
+ .expect("Content-Type", /json/)
318
353
  .expect(200)
319
-
354
+
320
355
  expect(res.body.valid).toBe(true)
321
356
  expect(Object.keys(res.body.errors)).toEqual([])
322
357
  await assertRowUsage(rowUsage)
@@ -331,9 +366,9 @@ describe("/rows", () => {
331
366
  .post(`/api/${table._id}/rows/validate`)
332
367
  .send({ name: 1 })
333
368
  .set(config.defaultHeaders())
334
- .expect('Content-Type', /json/)
369
+ .expect("Content-Type", /json/)
335
370
  .expect(200)
336
-
371
+
337
372
  expect(res.body.valid).toBe(false)
338
373
  expect(Object.keys(res.body.errors)).toEqual(["name"])
339
374
  await assertRowUsage(rowUsage)
@@ -351,19 +386,16 @@ describe("/rows", () => {
351
386
  const res = await request
352
387
  .delete(`/api/${table._id}/rows`)
353
388
  .send({
354
- rows: [
355
- row1,
356
- row2,
357
- ]
389
+ rows: [row1, row2],
358
390
  })
359
391
  .set(config.defaultHeaders())
360
- .expect('Content-Type', /json/)
392
+ .expect("Content-Type", /json/)
361
393
  .expect(200)
362
394
 
363
395
  expect(res.body.length).toEqual(2)
364
396
  await loadRow(row1._id, 404)
365
397
  await assertRowUsage(rowUsage - 2)
366
- await assertQueryUsage(queryUsage +1)
398
+ await assertQueryUsage(queryUsage + 1)
367
399
  })
368
400
  })
369
401
 
@@ -376,12 +408,12 @@ describe("/rows", () => {
376
408
  const res = await request
377
409
  .get(`/api/views/${table._id}`)
378
410
  .set(config.defaultHeaders())
379
- .expect('Content-Type', /json/)
411
+ .expect("Content-Type", /json/)
380
412
  .expect(200)
381
413
  expect(res.body.length).toEqual(1)
382
414
  expect(res.body[0]._id).toEqual(row._id)
383
415
  await assertRowUsage(rowUsage)
384
- await assertQueryUsage(queryUsage +1)
416
+ await assertQueryUsage(queryUsage + 1)
385
417
  })
386
418
 
387
419
  it("should throw an error if view doesn't exist", async () => {
@@ -406,7 +438,7 @@ describe("/rows", () => {
406
438
  const res = await request
407
439
  .get(`/api/views/${view.name}`)
408
440
  .set(config.defaultHeaders())
409
- .expect('Content-Type', /json/)
441
+ .expect("Content-Type", /json/)
410
442
  .expect(200)
411
443
  expect(res.body.length).toEqual(1)
412
444
  expect(res.body[0]._id).toEqual(row._id)
@@ -418,21 +450,24 @@ describe("/rows", () => {
418
450
 
419
451
  describe("fetchEnrichedRows", () => {
420
452
  it("should allow enriching some linked rows", async () => {
421
- const { table, firstRow, secondRow } = await doInTenant(setup.structures.TENANT_ID, async () => {
422
- const table = await config.createLinkedTable()
423
- const firstRow = await config.createRow({
424
- name: "Test Contact",
425
- description: "original description",
426
- tableId: table._id
427
- })
428
- const secondRow = await config.createRow({
429
- name: "Test 2",
430
- description: "og desc",
431
- link: [{_id: firstRow._id}],
432
- tableId: table._id,
433
- })
434
- return { table, firstRow, secondRow }
435
- })
453
+ const { table, firstRow, secondRow } = await doInTenant(
454
+ setup.structures.TENANT_ID,
455
+ async () => {
456
+ const table = await config.createLinkedTable()
457
+ const firstRow = await config.createRow({
458
+ name: "Test Contact",
459
+ description: "original description",
460
+ tableId: table._id,
461
+ })
462
+ const secondRow = await config.createRow({
463
+ name: "Test 2",
464
+ description: "og desc",
465
+ link: [{ _id: firstRow._id }],
466
+ tableId: table._id,
467
+ })
468
+ return { table, firstRow, secondRow }
469
+ }
470
+ )
436
471
  const rowUsage = await getRowUsage()
437
472
  const queryUsage = await getQueryUsage()
438
473
 
@@ -440,7 +475,7 @@ describe("/rows", () => {
440
475
  const resBasic = await request
441
476
  .get(`/api/${table._id}/rows/${secondRow._id}`)
442
477
  .set(config.defaultHeaders())
443
- .expect('Content-Type', /json/)
478
+ .expect("Content-Type", /json/)
444
479
  .expect(200)
445
480
  expect(resBasic.body.link[0]._id).toBe(firstRow._id)
446
481
  expect(resBasic.body.link[0].primaryDisplay).toBe("Test Contact")
@@ -449,14 +484,14 @@ describe("/rows", () => {
449
484
  const resEnriched = await request
450
485
  .get(`/api/${table._id}/${secondRow._id}/enrich`)
451
486
  .set(config.defaultHeaders())
452
- .expect('Content-Type', /json/)
487
+ .expect("Content-Type", /json/)
453
488
  .expect(200)
454
489
  expect(resEnriched.body.link.length).toBe(1)
455
490
  expect(resEnriched.body.link[0]._id).toBe(firstRow._id)
456
491
  expect(resEnriched.body.link[0].name).toBe("Test Contact")
457
492
  expect(resEnriched.body.link[0].description).toBe("original description")
458
493
  await assertRowUsage(rowUsage)
459
- await assertQueryUsage(queryUsage +2)
494
+ await assertQueryUsage(queryUsage + 2)
460
495
  })
461
496
  })
462
497
 
@@ -466,9 +501,11 @@ describe("/rows", () => {
466
501
  const row = await config.createRow({
467
502
  name: "test",
468
503
  description: "test",
469
- attachment: [{
470
- key: `${config.getAppId()}/attachments/test/thing.csv`,
471
- }],
504
+ attachment: [
505
+ {
506
+ key: `${config.getAppId()}/attachments/test/thing.csv`,
507
+ },
508
+ ],
472
509
  tableId: table._id,
473
510
  })
474
511
  // the environment needs configured for this
@@ -482,4 +519,49 @@ describe("/rows", () => {
482
519
  })
483
520
  })
484
521
  })
522
+
523
+ describe("exportData", () => {
524
+ it("should allow exporting all columns", async () => {
525
+ const existing = await config.createRow()
526
+ const res = await request
527
+ .post(`/api/${table._id}/rows/exportRows?format=json`)
528
+ .set(config.defaultHeaders())
529
+ .send({
530
+ rows: [existing._id],
531
+ })
532
+ .expect("Content-Type", /json/)
533
+ .expect(200)
534
+ const results = JSON.parse(res.text)
535
+ expect(results.length).toEqual(1)
536
+ const row = results[0]
537
+
538
+ // Ensure all original columns were exported
539
+ expect(Object.keys(row).length).toBeGreaterThanOrEqual(
540
+ Object.keys(existing).length
541
+ )
542
+ Object.keys(existing).forEach(key => {
543
+ expect(row[key]).toEqual(existing[key])
544
+ })
545
+ })
546
+
547
+ it("should allow exporting only certain columns", async () => {
548
+ const existing = await config.createRow()
549
+ const res = await request
550
+ .post(`/api/${table._id}/rows/exportRows?format=json`)
551
+ .set(config.defaultHeaders())
552
+ .send({
553
+ rows: [existing._id],
554
+ columns: ["_id"],
555
+ })
556
+ .expect("Content-Type", /json/)
557
+ .expect(200)
558
+ const results = JSON.parse(res.text)
559
+ expect(results.length).toEqual(1)
560
+ const row = results[0]
561
+
562
+ // Ensure only the _id column was exported
563
+ expect(Object.keys(row).length).toEqual(1)
564
+ expect(row._id).toEqual(existing._id)
565
+ })
566
+ })
485
567
  })
@@ -24,7 +24,7 @@ const Runner = new Thread(ThreadType.AUTOMATION)
24
24
  export async function processEvent(job: any) {
25
25
  try {
26
26
  console.log(
27
- `${job.data.automation.appId} automation ${job.data.automation._id} running`
27
+ `${job.data.automation.appId} automation ${job.data.automation._id} running. jobId=${job.id}`
28
28
  )
29
29
  // need to actually await these so that an error can be captured properly
30
30
  const tenantId = tenancy.getTenantIDFromAppID(job.data.event.appId)