@budibase/server 1.2.33-alpha.1 → 1.2.35

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 (190) hide show
  1. package/__mocks__/mongodb.ts +0 -4
  2. package/__mocks__/node-fetch.ts +1 -8
  3. package/builder/assets/index.05962580.js +975 -0
  4. package/builder/assets/{index.f1c7e247.css → index.08dd0c5e.css} +1 -1
  5. package/builder/index.html +2 -2
  6. package/coverage/clover.xml +469 -466
  7. package/coverage/coverage-final.json +17 -17
  8. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/index.html +1 -1
  17. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/migrations.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/validation.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/index.html +25 -25
  28. package/coverage/lcov-report/api/controllers/row/internal.js.html +14 -14
  29. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +191 -209
  30. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/row/utils.js.html +18 -27
  32. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/table/external.js.html +2 -2
  36. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  37. package/coverage/lcov-report/api/controllers/table/index.js.html +3 -3
  38. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/user.js.html +19 -19
  40. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  42. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  46. package/coverage/lcov-report/api/index.html +1 -1
  47. package/coverage/lcov-report/api/index.js.html +1 -1
  48. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/index.html +1 -1
  59. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/utils/index.html +1 -1
  73. package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  76. package/coverage/lcov-report/automations/actions.js.html +1 -1
  77. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  78. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  79. package/coverage/lcov-report/automations/index.html +1 -1
  80. package/coverage/lcov-report/automations/index.js.html +1 -1
  81. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  82. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/index.html +18 -18
  88. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/queryRows.js.html +122 -26
  92. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/utils.js.html +9 -9
  97. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  98. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  107. package/coverage/lcov-report/constants/index.html +1 -1
  108. package/coverage/lcov-report/constants/index.js.html +30 -30
  109. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  110. package/coverage/lcov-report/constants/screens.js.html +1 -1
  111. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  112. package/coverage/lcov-report/db/index.html +1 -1
  113. package/coverage/lcov-report/db/index.js.html +1 -1
  114. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  115. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  116. package/coverage/lcov-report/db/linkedRows/index.js.html +11 -11
  117. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +7 -7
  118. package/coverage/lcov-report/db/newid.js.html +3 -3
  119. package/coverage/lcov-report/db/utils.js.html +61 -61
  120. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  121. package/coverage/lcov-report/events/index.html +1 -1
  122. package/coverage/lcov-report/events/index.js.html +1 -1
  123. package/coverage/lcov-report/events/utils.js.html +1 -1
  124. package/coverage/lcov-report/index.html +29 -29
  125. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  126. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  127. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  128. package/coverage/lcov-report/middleware/builder.js.html +1 -1
  129. package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
  130. package/coverage/lcov-report/middleware/index.html +1 -1
  131. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  132. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  133. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  134. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  135. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  136. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  137. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  138. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  139. package/coverage/lcov-report/utilities/global.js.html +16 -16
  140. package/coverage/lcov-report/utilities/index.html +1 -1
  141. package/coverage/lcov-report/utilities/index.js.html +23 -23
  142. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
  143. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  144. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  145. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  146. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  147. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +10 -10
  148. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +8 -8
  149. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  150. package/coverage/lcov-report/utilities/security.js.html +1 -1
  151. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  152. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  153. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  154. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  155. package/coverage/lcov-report/utilities/users.js.html +7 -7
  156. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  157. package/coverage/lcov.info +765 -749
  158. package/dist/api/controllers/row/internalSearch.js +0 -5
  159. package/dist/api/controllers/row/utils.js +1 -3
  160. package/dist/api/controllers/table/external.js +1 -1
  161. package/dist/automations/logging/index.js +0 -3
  162. package/dist/automations/steps/queryRows.js +27 -2
  163. package/dist/integrations/base/sql.js +4 -5
  164. package/dist/integrations/base/utils.js +27 -13
  165. package/dist/integrations/microsoftSqlServer.js +2 -5
  166. package/dist/integrations/mongodb.js +8 -35
  167. package/dist/integrations/mysql.js +2 -2
  168. package/dist/integrations/postgres.js +2 -5
  169. package/dist/package.json +7 -7
  170. package/dist/tsconfig.build.tsbuildinfo +1 -1
  171. package/package.json +8 -8
  172. package/src/api/controllers/row/internalSearch.js +0 -6
  173. package/src/api/controllers/row/utils.js +1 -4
  174. package/src/api/controllers/table/external.js +1 -1
  175. package/src/automations/logging/index.ts +0 -3
  176. package/src/automations/steps/queryRows.js +34 -2
  177. package/src/automations/tests/queryRows.spec.js +67 -1
  178. package/src/integrations/base/sql.ts +4 -5
  179. package/src/integrations/base/utils.ts +19 -9
  180. package/src/integrations/microsoftSqlServer.ts +2 -3
  181. package/src/integrations/mongodb.ts +8 -35
  182. package/src/integrations/mysql.ts +1 -1
  183. package/src/integrations/postgres.ts +1 -2
  184. package/src/integrations/queries/sql.ts +1 -0
  185. package/src/integrations/tests/mongo.spec.js +0 -218
  186. package/src/integrations/tests/sql.spec.js +1 -1
  187. package/builder/assets/index.6cf8bf4f.js +0 -977
  188. package/dist/integrations/base/query.js +0 -27
  189. package/src/api/routes/tests/internalSearch.spec.js +0 -157
  190. package/src/integrations/base/query.ts +0 -17
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.33-alpha.1",
4
+ "version": "1.2.35",
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.33-alpha.1",
81
- "@budibase/client": "1.2.33-alpha.1",
82
- "@budibase/pro": "1.2.33-alpha.0",
83
- "@budibase/string-templates": "1.2.33-alpha.1",
84
- "@budibase/types": "1.2.33-alpha.1",
80
+ "@budibase/backend-core": "^1.2.35",
81
+ "@budibase/client": "^1.2.35",
82
+ "@budibase/pro": "1.2.34",
83
+ "@budibase/string-templates": "^1.2.35",
84
+ "@budibase/types": "^1.2.35",
85
85
  "@bull-board/api": "3.7.0",
86
86
  "@bull-board/koa": "3.9.4",
87
87
  "@elastic/elasticsearch": "7.10.0",
@@ -106,7 +106,7 @@
106
106
  "google-auth-library": "7.12.0",
107
107
  "google-spreadsheet": "3.2.0",
108
108
  "jimp": "0.16.1",
109
- "joi": "17.6.0",
109
+ "joi": "17.2.1",
110
110
  "js-yaml": "4.1.0",
111
111
  "jsonschema": "1.4.0",
112
112
  "knex": "0.95.15",
@@ -195,5 +195,5 @@
195
195
  "optionalDependencies": {
196
196
  "oracledb": "5.3.0"
197
197
  },
198
- "gitHead": "8e7169e0647d7f5c133e9b49a37bd7428eca743a"
198
+ "gitHead": "a1c1185fc5dcdaf0c363565a97436b6933bb174c"
199
199
  }
@@ -1,5 +1,4 @@
1
1
  const { SearchIndexes } = require("../../../db/utils")
2
- const { removeKeyNumbering } = require("./utils")
3
2
  const fetch = require("node-fetch")
4
3
  const { getCouchInfo } = require("@budibase/backend-core/db")
5
4
  const { getAppId } = require("@budibase/backend-core/context")
@@ -198,8 +197,6 @@ class QueryBuilder {
198
197
 
199
198
  function build(structure, queryFn) {
200
199
  for (let [key, value] of Object.entries(structure)) {
201
- // check for new format - remove numbering if needed
202
- key = removeKeyNumbering(key)
203
200
  key = builder.preprocess(key.replace(/ /g, "_"), {
204
201
  escape: true,
205
202
  })
@@ -313,9 +310,6 @@ class QueryBuilder {
313
310
  }
314
311
  }
315
312
 
316
- // exported for unit testing
317
- exports.QueryBuilder = QueryBuilder
318
-
319
313
  /**
320
314
  * Executes a lucene search query.
321
315
  * @param url The query URL
@@ -3,9 +3,8 @@ const { cloneDeep } = require("lodash/fp")
3
3
  const { InternalTables } = require("../../../db/utils")
4
4
  const userController = require("../user")
5
5
  const { FieldTypes } = require("../../../constants")
6
+ const { makeExternalQuery } = require("../../../integrations/base/utils")
6
7
  const { getAppDB } = require("@budibase/backend-core/context")
7
- const { makeExternalQuery } = require("../../../integrations/base/query")
8
- const { removeKeyNumbering } = require("../../../integrations/base/utils")
9
8
 
10
9
  validateJs.extend(validateJs.validators.datetime, {
11
10
  parse: function (value) {
@@ -17,8 +16,6 @@ validateJs.extend(validateJs.validators.datetime, {
17
16
  },
18
17
  })
19
18
 
20
- exports.removeKeyNumbering = removeKeyNumbering
21
-
22
19
  exports.getDatasourceAndQuery = async json => {
23
20
  const datasourceId = json.endpoint.datasourceId
24
21
  const db = getAppDB()
@@ -14,7 +14,7 @@ const {
14
14
  FieldTypes,
15
15
  RelationshipTypes,
16
16
  } = require("../../../constants")
17
- const { makeExternalQuery } = require("../../../integrations/base/query")
17
+ const { makeExternalQuery } = require("../../../integrations/base/utils")
18
18
  const { cloneDeep } = require("lodash/fp")
19
19
  const csvParser = require("../../../utilities/csvParser")
20
20
  const { handleRequest } = require("../row/external")
@@ -23,9 +23,6 @@ export async function checkAppMetadata(apps: App[]) {
23
23
  for (let [key, errors] of Object.entries(metadata.automationErrors)) {
24
24
  const updated = []
25
25
  for (let error of errors) {
26
- if (!error) {
27
- continue
28
- }
29
26
  const startDate = error.split(dbUtils.SEPARATOR)[2]
30
27
  if (startDate > maxStartDate) {
31
28
  updated.push(error)
@@ -14,6 +14,16 @@ const SortOrdersPretty = {
14
14
  [SortOrders.DESCENDING]: "Descending",
15
15
  }
16
16
 
17
+ const EmptyFilterOptions = {
18
+ RETURN_ALL: "all",
19
+ RETURN_NONE: "none",
20
+ }
21
+
22
+ const EmptyFilterOptionsPretty = {
23
+ [EmptyFilterOptions.RETURN_ALL]: "Return all table rows",
24
+ [EmptyFilterOptions.RETURN_NONE]: "Return no rows",
25
+ }
26
+
17
27
  exports.definition = {
18
28
  description: "Query rows from the database",
19
29
  icon: "Search",
@@ -52,6 +62,12 @@ exports.definition = {
52
62
  title: "Limit",
53
63
  customType: "queryLimit",
54
64
  },
65
+ onEmptyFilter: {
66
+ pretty: Object.values(EmptyFilterOptionsPretty),
67
+ enum: Object.values(EmptyFilterOptions),
68
+ type: "string",
69
+ title: "When Filter Empty",
70
+ },
55
71
  },
56
72
  required: ["tableId"],
57
73
  },
@@ -103,6 +119,10 @@ function typeCoercion(filters, table) {
103
119
  return filters
104
120
  }
105
121
 
122
+ const hasNullFilters = filters =>
123
+ filters.length === 0 ||
124
+ filters.some(filter => filter.value === null || filter.value === "")
125
+
106
126
  exports.run = async function ({ inputs, appId }) {
107
127
  const { tableId, filters, sortColumn, sortOrder, limit } = inputs
108
128
  const table = await getTable(appId, tableId)
@@ -127,9 +147,21 @@ exports.run = async function ({ inputs, appId }) {
127
147
  version: "1",
128
148
  })
129
149
  try {
130
- await rowController.search(ctx)
150
+ let rows
151
+
152
+ if (
153
+ inputs.onEmptyFilter === EmptyFilterOptions.RETURN_NONE &&
154
+ inputs["filters-def"] &&
155
+ hasNullFilters(inputs["filters-def"])
156
+ ) {
157
+ rows = []
158
+ } else {
159
+ await rowController.search(ctx)
160
+ rows = ctx.body ? ctx.body.rows : []
161
+ }
162
+
131
163
  return {
132
- rows: ctx.body ? ctx.body.rows : [],
164
+ rows,
133
165
  success: ctx.status === 200,
134
166
  }
135
167
  } catch (err) {
@@ -16,7 +16,7 @@ describe("Test a query step automation", () => {
16
16
  let table
17
17
  let config = setup.getConfig()
18
18
 
19
- beforeEach(async () => {
19
+ beforeAll(async () => {
20
20
  await config.init()
21
21
  table = await config.createTable()
22
22
  const row = {
@@ -48,4 +48,70 @@ describe("Test a query step automation", () => {
48
48
  expect(res.rows.length).toBe(2)
49
49
  expect(res.rows[0].name).toBe(NAME)
50
50
  })
51
+
52
+ it("Returns all rows when onEmptyFilter has no value and no filters are passed", async () => {
53
+ const inputs = {
54
+ tableId: table._id,
55
+ filters: {},
56
+ sortColumn: "name",
57
+ sortOrder: "ascending",
58
+ limit: 10,
59
+ }
60
+ const res = await setup.runStep(setup.actions.QUERY_ROWS.stepId, inputs)
61
+ expect(res.success).toBe(true)
62
+ expect(res.rows).toBeDefined()
63
+ expect(res.rows.length).toBe(2)
64
+ expect(res.rows[0].name).toBe(NAME)
65
+ })
66
+
67
+ it("Returns no rows when onEmptyFilter is RETURN_NONE and theres no filters", async () => {
68
+ const inputs = {
69
+ tableId: table._id,
70
+ filters: {},
71
+ "filters-def": [],
72
+ sortColumn: "name",
73
+ sortOrder: "ascending",
74
+ limit: 10,
75
+ onEmptyFilter: "none",
76
+ }
77
+ const res = await setup.runStep(setup.actions.QUERY_ROWS.stepId, inputs)
78
+ expect(res.success).toBe(false)
79
+ expect(res.rows).toBeDefined()
80
+ expect(res.rows.length).toBe(0)
81
+ })
82
+
83
+ it("Returns no rows when onEmptyFilters RETURN_NONE and a filter is passed with a null value", async () => {
84
+ const inputs = {
85
+ tableId: table._id,
86
+ onEmptyFilter: "none",
87
+ filters: {},
88
+ "filters-def": [
89
+ {
90
+ value: null
91
+ }
92
+ ],
93
+ sortColumn: "name",
94
+ sortOrder: "ascending",
95
+ limit: 10,
96
+ }
97
+ const res = await setup.runStep(setup.actions.QUERY_ROWS.stepId, inputs)
98
+ expect(res.success).toBe(false)
99
+ expect(res.rows).toBeDefined()
100
+ expect(res.rows.length).toBe(0)
101
+ })
102
+
103
+ it("Returns rows when onEmptyFilter is RETURN_ALL and no filter is passed", async () => {
104
+ const inputs = {
105
+ tableId: table._id,
106
+ onEmptyFilter: "all",
107
+ filters: {},
108
+ sortColumn: "name",
109
+ sortOrder: "ascending",
110
+ limit: 10,
111
+ }
112
+ const res = await setup.runStep(setup.actions.QUERY_ROWS.stepId, inputs)
113
+ expect(res.success).toBe(true)
114
+ expect(res.rows).toBeDefined()
115
+ expect(res.rows.length).toBe(2)
116
+ })
51
117
  })
@@ -10,7 +10,6 @@ import {
10
10
  import { isIsoDateString, SqlClients } from "../utils"
11
11
  import SqlTableQueryBuilder from "./sqlTable"
12
12
  import environment from "../../environment"
13
- import { removeKeyNumbering } from "./utils"
14
13
 
15
14
  const envLimit = environment.SQL_MAX_ROWS
16
15
  ? parseInt(environment.SQL_MAX_ROWS)
@@ -134,13 +133,12 @@ class InternalBuilder {
134
133
  fn: (key: string, value: any) => void
135
134
  ) {
136
135
  for (let [key, value] of Object.entries(structure)) {
137
- const updatedKey = removeKeyNumbering(key)
138
- const isRelationshipField = updatedKey.includes(".")
136
+ const isRelationshipField = key.includes(".")
139
137
  if (!opts.relationship && !isRelationshipField) {
140
- fn(`${opts.tableName}.${updatedKey}`, value)
138
+ fn(`${opts.tableName}.${key}`, value)
141
139
  }
142
140
  if (opts.relationship && isRelationshipField) {
143
- fn(updatedKey, value)
141
+ fn(key, value)
144
142
  }
145
143
  }
146
144
  }
@@ -584,3 +582,4 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
584
582
  }
585
583
 
586
584
  export default SqlQueryBuilder
585
+ module.exports = SqlQueryBuilder
@@ -1,12 +1,22 @@
1
- const QUERY_START_REGEX = /\d[0-9]*:/g
1
+ import { QueryJson } from "../../definitions/datasource"
2
+ import { Datasource } from "../../definitions/common"
2
3
 
3
- export function removeKeyNumbering(key: any): string {
4
- if (typeof key === "string" && key.match(QUERY_START_REGEX) != null) {
5
- const parts = key.split(":")
6
- // remove the number
7
- parts.shift()
8
- return parts.join(":")
9
- } else {
10
- return key
4
+ module DatasourceUtils {
5
+ const { integrations } = require("../index")
6
+
7
+ export async function makeExternalQuery(
8
+ datasource: Datasource,
9
+ json: QueryJson
10
+ ) {
11
+ const Integration = integrations[datasource.source]
12
+ // query is the opinionated function
13
+ if (Integration.prototype.query) {
14
+ const integration = new Integration(datasource.config)
15
+ return integration.query(json)
16
+ } else {
17
+ throw "Datasource does not support query."
18
+ }
11
19
  }
20
+
21
+ module.exports.makeExternalQuery = makeExternalQuery
12
22
  }
@@ -15,10 +15,10 @@ import {
15
15
  } from "./utils"
16
16
  import { DatasourcePlus } from "./base/datasourcePlus"
17
17
  import { Table, TableSchema } from "../definitions/common"
18
- import Sql from "./base/sql"
19
18
 
20
19
  module MSSQLModule {
21
20
  const sqlServer = require("mssql")
21
+ const Sql = require("./base/sql")
22
22
  const DEFAULT_SCHEMA = "dbo"
23
23
 
24
24
  interface MSSQLConfig {
@@ -96,8 +96,7 @@ module MSSQLModule {
96
96
  class SqlServerIntegration extends Sql implements DatasourcePlus {
97
97
  private readonly config: MSSQLConfig
98
98
  private index: number = 0
99
- private readonly pool: any
100
- private client: any
99
+ static pool: any
101
100
  public tables: Record<string, Table> = {}
102
101
  public schemaErrors: Record<string, string> = {}
103
102
 
@@ -92,15 +92,12 @@ module MongoDBModule {
92
92
  if (json[field] instanceof Object) {
93
93
  json[field] = self.createObjectIds(json[field])
94
94
  }
95
- if (
96
- (field === "_id" || field?.startsWith("$")) &&
97
- typeof json[field] === "string"
98
- ) {
99
- const id = json[field].match(
95
+ if (field === "_id" && typeof json[field] === "string") {
96
+ const id = json["_id"].match(
100
97
  /(?<=objectid\(['"]).*(?=['"]\))/gi
101
98
  )?.[0]
102
99
  if (id) {
103
- json[field] = ObjectID.createFromHexString(id)
100
+ json["_id"] = ObjectID.createFromHexString(id)
104
101
  }
105
102
  }
106
103
  }
@@ -117,31 +114,10 @@ module MongoDBModule {
117
114
  }
118
115
 
119
116
  parseQueryParams(params: string, mode: string) {
120
- let queryParams = []
121
- let openCount = 0
122
- let inQuotes = false
123
- let i = 0
124
- let startIndex = 0
125
- for (let c of params) {
126
- if (c === '"' && i > 0 && params[i - 1] !== "\\") {
127
- inQuotes = !inQuotes
128
- }
129
- if (c === "{" && !inQuotes) {
130
- openCount++
131
- if (openCount === 1) {
132
- startIndex = i
133
- }
134
- } else if (c === "}" && !inQuotes) {
135
- if (openCount === 1) {
136
- queryParams.push(JSON.parse(params.substring(startIndex, i + 1)))
137
- }
138
- openCount--
139
- }
140
- i++
141
- }
142
- let group1 = queryParams[0] ?? {}
143
- let group2 = queryParams[1] ?? {}
144
- let group3 = queryParams[2] ?? {}
117
+ let queryParams = params.split(/(?<=}),[\n\s]*(?={)/g)
118
+ let group1 = queryParams[0] ? JSON.parse(queryParams[0]) : {}
119
+ let group2 = queryParams[1] ? JSON.parse(queryParams[1]) : {}
120
+ let group3 = queryParams[2] ? JSON.parse(queryParams[2]) : {}
145
121
  if (mode === "update") {
146
122
  return {
147
123
  filter: group1,
@@ -200,10 +176,7 @@ module MongoDBModule {
200
176
  return await collection.findOne(json)
201
177
  }
202
178
  case "findOneAndUpdate": {
203
- if (typeof query.json === "string") {
204
- json = this.parseQueryParams(query.json, "update")
205
- }
206
- let findAndUpdateJson = this.createObjectIds(json) as {
179
+ let findAndUpdateJson = json as {
207
180
  filter: FilterQuery<any>
208
181
  update: UpdateQuery<any>
209
182
  options: FindOneAndUpdateOption<any>
@@ -16,10 +16,10 @@ import {
16
16
  import { DatasourcePlus } from "./base/datasourcePlus"
17
17
  import dayjs from "dayjs"
18
18
  const { NUMBER_REGEX } = require("../utilities")
19
- import Sql from "./base/sql"
20
19
 
21
20
  module MySQLModule {
22
21
  const mysql = require("mysql2/promise")
22
+ const Sql = require("./base/sql")
23
23
 
24
24
  interface MySQLConfig {
25
25
  host: string
@@ -14,10 +14,10 @@ import {
14
14
  SqlClients,
15
15
  } from "./utils"
16
16
  import { DatasourcePlus } from "./base/datasourcePlus"
17
- import Sql from "./base/sql"
18
17
 
19
18
  module PostgresModule {
20
19
  const { Client, types } = require("pg")
20
+ const Sql = require("./base/sql")
21
21
  const { escapeDangerousCharacters } = require("../utilities")
22
22
 
23
23
  // Return "date" and "timestamp" types as plain strings.
@@ -117,7 +117,6 @@ module PostgresModule {
117
117
  private readonly client: any
118
118
  private readonly config: PostgresConfig
119
119
  private index: number = 1
120
- private open: boolean
121
120
  public tables: Record<string, Table> = {}
122
121
  public schemaErrors: Record<string, string> = {}
123
122
 
@@ -1,4 +1,5 @@
1
1
  import { findHBSBlocks, processStringSync } from "@budibase/string-templates"
2
+ import { Integration } from "../../definitions/datasource"
2
3
  import { DatasourcePlus } from "../base/datasourcePlus"
3
4
 
4
5
  const CONST_CHAR_REGEX = new RegExp("'[^']*'", "g")
@@ -102,222 +102,4 @@ describe("MongoDB Integration", () => {
102
102
  expect(error).toBeDefined()
103
103
  restore()
104
104
  })
105
-
106
- it("creates ObjectIds if the _id fields contains a match on ObjectId", async () => {
107
- const query = {
108
- json: {
109
- filter: {
110
- _id: "ObjectId('ACBD12345678ABCD12345678')",
111
- name: "ObjectId('name')"
112
- },
113
- update: {
114
- _id: "ObjectId('FFFF12345678ABCD12345678')",
115
- name: "ObjectId('updatedName')",
116
- },
117
- options: {
118
- upsert: false,
119
- },
120
- },
121
- extra: { collection: "testCollection", actionTypes: "updateOne" },
122
- }
123
- await config.integration.update(query)
124
- expect(config.integration.client.updateOne).toHaveBeenCalled()
125
-
126
- const args = config.integration.client.updateOne.mock.calls[0]
127
- expect(args[0]).toEqual({
128
- _id: mongo.ObjectID.createFromHexString("ACBD12345678ABCD12345678"),
129
- name: "ObjectId('name')",
130
- })
131
- expect(args[1]).toEqual({
132
- _id: mongo.ObjectID.createFromHexString("FFFF12345678ABCD12345678"),
133
- name: "ObjectId('updatedName')",
134
- })
135
- expect(args[2]).toEqual({
136
- upsert: false
137
- })
138
- })
139
-
140
- it("creates ObjectIds if the $ operator fields contains a match on ObjectId", async () => {
141
- const query = {
142
- json: {
143
- filter: {
144
- _id: {
145
- $eq: "ObjectId('ACBD12345678ABCD12345678')",
146
- }
147
- },
148
- update: {
149
- $set: {
150
- _id: "ObjectId('FFFF12345678ABCD12345678')",
151
- },
152
- },
153
- options: {
154
- upsert: true,
155
- },
156
- },
157
- extra: { collection: "testCollection", actionTypes: "updateOne" },
158
- }
159
- await config.integration.update(query)
160
- expect(config.integration.client.updateOne).toHaveBeenCalled()
161
-
162
- const args = config.integration.client.updateOne.mock.calls[0]
163
- expect(args[0]).toEqual({
164
- _id: {
165
- $eq: mongo.ObjectID.createFromHexString("ACBD12345678ABCD12345678"),
166
- }
167
- })
168
- expect(args[1]).toEqual({
169
- $set: {
170
- _id: mongo.ObjectID.createFromHexString("FFFF12345678ABCD12345678"),
171
- }
172
- })
173
- expect(args[2]).toEqual({
174
- upsert: true
175
- })
176
- })
177
-
178
- it("supports findOneAndUpdate", async () => {
179
- const query = {
180
- json: {
181
- filter: {
182
- _id: {
183
- $eq: "ObjectId('ACBD12345678ABCD12345678')",
184
- }
185
- },
186
- update: {
187
- $set: {
188
- name: "UPDATED",
189
- age: 99
190
- },
191
- },
192
- options: {
193
- upsert: false,
194
- },
195
- },
196
- extra: { collection: "testCollection", actionTypes: "findOneAndUpdate" },
197
- }
198
- await config.integration.read(query)
199
- expect(config.integration.client.findOneAndUpdate).toHaveBeenCalled()
200
-
201
- const args = config.integration.client.findOneAndUpdate.mock.calls[0]
202
- expect(args[0]).toEqual({
203
- _id: {
204
- $eq: mongo.ObjectID.createFromHexString("ACBD12345678ABCD12345678"),
205
- }
206
- })
207
- expect(args[1]).toEqual({
208
- $set: {
209
- name: "UPDATED",
210
- age: 99
211
- }
212
- })
213
- expect(args[2]).toEqual({
214
- upsert: false
215
- })
216
- })
217
-
218
- it("can parse nested objects with arrays", async () => {
219
- const query = {
220
- json: `{
221
- "_id": {
222
- "$eq": "ObjectId('ACBD12345678ABCD12345678')"
223
- }
224
- },
225
- {
226
- "$set": {
227
- "value": {
228
- "data": [
229
- { "cid": 1 },
230
- { "cid": 2 },
231
- { "nested": {
232
- "name": "test"
233
- }}
234
- ]
235
- }
236
- }
237
- },
238
- {
239
- "upsert": true
240
- }`,
241
- extra: { collection: "testCollection", actionTypes: "updateOne" },
242
- }
243
- await config.integration.update(query)
244
- expect(config.integration.client.updateOne).toHaveBeenCalled()
245
-
246
- const args = config.integration.client.updateOne.mock.calls[0]
247
- expect(args[0]).toEqual({
248
- _id: {
249
- $eq: mongo.ObjectID.createFromHexString("ACBD12345678ABCD12345678"),
250
- }
251
- })
252
- expect(args[1]).toEqual({
253
- $set: {
254
- value: {
255
- data: [
256
- { cid: 1 },
257
- { cid: 2 },
258
- { nested: {
259
- name: "test"
260
- }}
261
- ]
262
- },
263
- },
264
- })
265
- expect(args[2]).toEqual({
266
- upsert: true
267
- })
268
- })
269
-
270
- it("ignores braces within strings when parsing nested objects", async () => {
271
- const query = {
272
- json: `{
273
- "_id": {
274
- "$eq": "ObjectId('ACBD12345678ABCD12345678')"
275
- }
276
- },
277
- {
278
- "$set": {
279
- "value": {
280
- "data": [
281
- { "cid": 1 },
282
- { "cid": 2 },
283
- { "nested": {
284
- "name": "te}st"
285
- }}
286
- ]
287
- }
288
- }
289
- },
290
- {
291
- "upsert": true,
292
- "extra": "ad\\"{\\"d"
293
- }`,
294
- extra: { collection: "testCollection", actionTypes: "updateOne" },
295
- }
296
- await config.integration.update(query)
297
- expect(config.integration.client.updateOne).toHaveBeenCalled()
298
-
299
- const args = config.integration.client.updateOne.mock.calls[0]
300
- expect(args[0]).toEqual({
301
- _id: {
302
- $eq: mongo.ObjectID.createFromHexString("ACBD12345678ABCD12345678"),
303
- }
304
- })
305
- expect(args[1]).toEqual({
306
- $set: {
307
- value: {
308
- data: [
309
- { cid: 1 },
310
- { cid: 2 },
311
- { nested: {
312
- name: "te}st"
313
- }}
314
- ]
315
- },
316
- },
317
- })
318
- expect(args[2]).toEqual({
319
- upsert: true,
320
- extra: "ad\"{\"d"
321
- })
322
- })
323
105
  })
@@ -1,4 +1,4 @@
1
- const Sql = require("../base/sql").default
1
+ const Sql = require("../base/sql")
2
2
  const { SqlClients } = require("../utils")
3
3
 
4
4
  const TABLE_NAME = "test"