@budibase/server 1.2.58 → 1.3.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 (211) hide show
  1. package/__mocks__/mongodb.ts +4 -0
  2. package/__mocks__/node-fetch.ts +8 -1
  3. package/builder/assets/index.00650f14.js +875 -0
  4. package/builder/assets/index.e50bda9f.css +6 -0
  5. package/builder/assets/{vendor.6bcafa60.js → vendor.67dbd8fa.js} +1 -1
  6. package/builder/index.html +3 -3
  7. package/coverage/clover.xml +549 -524
  8. package/coverage/coverage-final.json +20 -20
  9. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +1 -1
  18. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  24. package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/index.html +25 -25
  29. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +317 -191
  31. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
  32. package/coverage/lcov-report/api/controllers/row/utils.js.html +27 -18
  33. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/table/external.js.html +2 -2
  37. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  38. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/user.js.html +19 -19
  41. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  46. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  47. package/coverage/lcov-report/api/index.html +1 -1
  48. package/coverage/lcov-report/api/index.js.html +5 -5
  49. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/index.html +1 -1
  60. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/utils/index.html +1 -1
  74. package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  77. package/coverage/lcov-report/automations/actions.js.html +1 -1
  78. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  79. package/coverage/lcov-report/automations/bullboard.js.html +9 -6
  80. package/coverage/lcov-report/automations/index.html +11 -11
  81. package/coverage/lcov-report/automations/index.js.html +1 -1
  82. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/index.html +1 -1
  89. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  108. package/coverage/lcov-report/constants/index.html +1 -1
  109. package/coverage/lcov-report/constants/index.js.html +30 -30
  110. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  111. package/coverage/lcov-report/constants/screens.js.html +1 -1
  112. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  113. package/coverage/lcov-report/db/index.html +1 -1
  114. package/coverage/lcov-report/db/index.js.html +1 -1
  115. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  116. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  117. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  118. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  119. package/coverage/lcov-report/db/newid.js.html +4 -4
  120. package/coverage/lcov-report/db/utils.js.html +73 -73
  121. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  122. package/coverage/lcov-report/events/index.html +1 -1
  123. package/coverage/lcov-report/events/index.js.html +1 -1
  124. package/coverage/lcov-report/events/utils.js.html +1 -1
  125. package/coverage/lcov-report/index.html +33 -33
  126. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  127. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  128. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  129. package/coverage/lcov-report/middleware/builder.js.html +12 -12
  130. package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
  131. package/coverage/lcov-report/middleware/index.html +10 -10
  132. package/coverage/lcov-report/middleware/joi-validator.js.html +18 -9
  133. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  134. package/coverage/lcov-report/middleware/resourceId.js.html +12 -12
  135. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  136. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  137. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  138. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  139. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  140. package/coverage/lcov-report/utilities/global.js.html +31 -31
  141. package/coverage/lcov-report/utilities/index.html +1 -1
  142. package/coverage/lcov-report/utilities/index.js.html +24 -24
  143. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  144. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  145. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  146. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  147. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  148. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  149. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  150. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  151. package/coverage/lcov-report/utilities/security.js.html +2 -2
  152. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  153. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  154. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +20 -20
  155. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  156. package/coverage/lcov-report/utilities/users.js.html +7 -7
  157. package/coverage/lcov-report/utilities/workerRequests.js.html +13 -13
  158. package/coverage/lcov.info +888 -844
  159. package/dist/api/controllers/application.js +80 -14
  160. package/dist/api/controllers/row/internalSearch.js +39 -4
  161. package/dist/api/controllers/row/utils.js +3 -1
  162. package/dist/api/controllers/static/index.js +26 -2
  163. package/dist/api/controllers/static/templates/preview.hbs +103 -0
  164. package/dist/api/controllers/table/external.js +1 -1
  165. package/dist/api/routes/static.js +3 -0
  166. package/dist/app.js +4 -3
  167. package/dist/automations/bullboard.js +1 -0
  168. package/dist/automations/logging/index.js +3 -0
  169. package/dist/integrations/base/query.js +27 -0
  170. package/dist/integrations/base/sql.js +62 -30
  171. package/dist/integrations/base/utils.js +13 -27
  172. package/dist/integrations/microsoftSqlServer.js +5 -2
  173. package/dist/integrations/mongodb.js +35 -8
  174. package/dist/integrations/mysql.js +2 -2
  175. package/dist/integrations/postgres.js +5 -2
  176. package/dist/middleware/joi-validator.js +7 -4
  177. package/dist/package.json +7 -7
  178. package/dist/threads/index.js +1 -0
  179. package/dist/tsconfig.build.tsbuildinfo +1 -1
  180. package/dist/utilities/fileSystem/index.js +2 -1
  181. package/dist/utilities/redis.js +1 -0
  182. package/package.json +8 -8
  183. package/src/api/controllers/application.ts +96 -15
  184. package/src/api/controllers/row/internalSearch.js +45 -3
  185. package/src/api/controllers/row/utils.js +4 -1
  186. package/src/api/controllers/static/index.ts +21 -1
  187. package/src/api/controllers/static/templates/preview.hbs +103 -0
  188. package/src/api/controllers/table/external.js +1 -1
  189. package/src/api/routes/static.ts +12 -0
  190. package/src/api/routes/tests/application.spec.js +26 -0
  191. package/src/api/routes/tests/data/old-app.txt +3 -0
  192. package/src/api/routes/tests/internalSearch.spec.js +176 -0
  193. package/src/api/routes/tests/static.spec.js +19 -7
  194. package/src/app.ts +5 -3
  195. package/src/automations/bullboard.js +1 -0
  196. package/src/automations/logging/index.ts +3 -0
  197. package/src/integrations/base/query.ts +16 -0
  198. package/src/integrations/base/sql.ts +67 -30
  199. package/src/integrations/base/utils.ts +9 -18
  200. package/src/integrations/microsoftSqlServer.ts +3 -2
  201. package/src/integrations/mongodb.ts +35 -8
  202. package/src/integrations/mysql.ts +1 -1
  203. package/src/integrations/postgres.ts +2 -1
  204. package/src/integrations/tests/mongo.spec.js +218 -0
  205. package/src/integrations/tests/sql.spec.js +101 -11
  206. package/src/middleware/joi-validator.js +7 -4
  207. package/src/threads/index.ts +1 -0
  208. package/src/utilities/fileSystem/index.js +2 -0
  209. package/src/utilities/redis.js +1 -0
  210. package/builder/assets/index.08dd0c5e.css +0 -6
  211. package/builder/assets/index.5cf58e77.js +0 -975
@@ -0,0 +1,176 @@
1
+ const search = require("../../controllers/row/internalSearch")
2
+ // this will be mocked out for _search endpoint
3
+ const fetch = require("node-fetch")
4
+ const PARAMS = {
5
+ tableId: "ta_12345679abcdef",
6
+ version: "1",
7
+ bookmark: null,
8
+ sort: null,
9
+ sortOrder: "ascending",
10
+ sortType: "string",
11
+ }
12
+
13
+ function checkLucene(resp, expected, params = PARAMS) {
14
+ const query = resp.rows[0].query
15
+ const json = JSON.parse(query)
16
+ if (PARAMS.sort) {
17
+ expect(json.sort).toBe(`${PARAMS.sort}<${PARAMS.sortType}>`)
18
+ }
19
+ if (PARAMS.bookmark) {
20
+ expect(json.bookmark).toBe(PARAMS.bookmark)
21
+ }
22
+ expect(json.include_docs).toBe(true)
23
+ expect(json.q).toBe(`(${expected}) AND tableId:"${params.tableId}"`)
24
+ expect(json.limit).toBe(params.limit || 50)
25
+ }
26
+
27
+ describe("internal search", () => {
28
+ it("default query", async () => {
29
+ const response = await search.paginatedSearch({
30
+ }, PARAMS)
31
+ checkLucene(response, `*:*`)
32
+ })
33
+
34
+ it("test equal query", async () => {
35
+ const response = await search.paginatedSearch({
36
+ equal: {
37
+ "column": "1",
38
+ }
39
+ }, PARAMS)
40
+ checkLucene(response, `*:* AND column:"1"`)
41
+ })
42
+
43
+ it("test notEqual query", async () => {
44
+ const response = await search.paginatedSearch({
45
+ notEqual: {
46
+ "column": "1",
47
+ }
48
+ }, PARAMS)
49
+ checkLucene(response, `*:* AND !column:"1"`)
50
+ })
51
+
52
+ it("test OR query", async () => {
53
+ const response = await search.paginatedSearch({
54
+ allOr: true,
55
+ equal: {
56
+ "column": "2",
57
+ },
58
+ notEqual: {
59
+ "column": "1",
60
+ }
61
+ }, PARAMS)
62
+ checkLucene(response, `column:"2" OR !column:"1"`)
63
+ })
64
+
65
+ it("test AND query", async () => {
66
+ const response = await search.paginatedSearch({
67
+ equal: {
68
+ "column": "2",
69
+ },
70
+ notEqual: {
71
+ "column": "1",
72
+ }
73
+ }, PARAMS)
74
+ checkLucene(response, `*:* AND column:"2" AND !column:"1"`)
75
+ })
76
+
77
+ it("test pagination query", async () => {
78
+ const updatedParams = {
79
+ ...PARAMS,
80
+ limit: 100,
81
+ bookmark: "awd",
82
+ sort: "column",
83
+ }
84
+ const response = await search.paginatedSearch({
85
+ string: {
86
+ "column": "2",
87
+ },
88
+ }, updatedParams)
89
+ checkLucene(response, `*:* AND column:2*`, updatedParams)
90
+ })
91
+
92
+ it("test range query", async () => {
93
+ const response = await search.paginatedSearch({
94
+ range: {
95
+ "column": { low: 1, high: 2 },
96
+ },
97
+ }, PARAMS)
98
+ checkLucene(response, `*:* AND column:[1 TO 2]`, PARAMS)
99
+ })
100
+
101
+ it("test empty query", async () => {
102
+ const response = await search.paginatedSearch({
103
+ empty: {
104
+ "column": "",
105
+ },
106
+ }, PARAMS)
107
+ checkLucene(response, `*:* AND !column:["" TO *]`, PARAMS)
108
+ })
109
+
110
+ it("test notEmpty query", async () => {
111
+ const response = await search.paginatedSearch({
112
+ notEmpty: {
113
+ "column": "",
114
+ },
115
+ }, PARAMS)
116
+ checkLucene(response, `*:* AND column:["" TO *]`, PARAMS)
117
+ })
118
+
119
+ it("test oneOf query", async () => {
120
+ const response = await search.paginatedSearch({
121
+ oneOf: {
122
+ "column": ["a", "b"],
123
+ },
124
+ }, PARAMS)
125
+ checkLucene(response, `*:* AND column:("a" OR "b")`, PARAMS)
126
+ })
127
+
128
+ it("test contains query", async () => {
129
+ const response = await search.paginatedSearch({
130
+ contains: {
131
+ "column": "a",
132
+ "colArr": [1, 2, 3],
133
+ },
134
+ }, PARAMS)
135
+ checkLucene(response, `*:* AND column:a AND colArr:(1 AND 2 AND 3)`, PARAMS)
136
+ })
137
+
138
+ it("test multiple of same column", async () => {
139
+ const response = await search.paginatedSearch({
140
+ allOr: true,
141
+ equal: {
142
+ "1:column": "a",
143
+ "2:column": "b",
144
+ "3:column": "c",
145
+ },
146
+ }, PARAMS)
147
+ checkLucene(response, `column:"a" OR column:"b" OR column:"c"`, PARAMS)
148
+ })
149
+
150
+ it("check a weird case for lucene building", async () => {
151
+ const response = await search.paginatedSearch({
152
+ equal: {
153
+ "1:1:column": "a",
154
+ },
155
+ }, PARAMS)
156
+ checkLucene(response, `*:* AND 1\\:column:"a"`, PARAMS)
157
+ })
158
+
159
+ it("test containsAny query", async () => {
160
+ const response = await search.paginatedSearch({
161
+ containsAny: {
162
+ "column": ["a", "b", "c"]
163
+ },
164
+ }, PARAMS)
165
+ checkLucene(response, `*:* AND column:(a OR b OR c)`, PARAMS)
166
+ })
167
+
168
+ it("test notContains query", async () => {
169
+ const response = await search.paginatedSearch({
170
+ notContains: {
171
+ "column": ["a", "b", "c"]
172
+ },
173
+ }, PARAMS)
174
+ checkLucene(response, `*:* AND NOT column:(a AND b AND c)`, PARAMS)
175
+ })
176
+ })
@@ -40,7 +40,6 @@ describe("/static", () => {
40
40
  })
41
41
 
42
42
  describe("/app", () => {
43
-
44
43
  beforeEach(() => {
45
44
  jest.clearAllMocks()
46
45
  })
@@ -60,7 +59,7 @@ describe("/static", () => {
60
59
  it("should serve the app by url", async () => {
61
60
  const headers = config.defaultHeaders()
62
61
  delete headers[constants.Headers.APP_ID]
63
-
62
+
64
63
  const res = await request
65
64
  .get(`/app${config.prodApp.url}`)
66
65
  .set(headers)
@@ -82,7 +81,7 @@ describe("/static", () => {
82
81
  describe("/attachments", () => {
83
82
  describe("generateSignedUrls", () => {
84
83
  let datasource
85
-
84
+
86
85
  beforeEach(async () => {
87
86
  datasource = await config.createDatasource({
88
87
  datasource: {
@@ -93,7 +92,7 @@ describe("/static", () => {
93
92
  },
94
93
  })
95
94
  })
96
-
95
+
97
96
  it("should be able to generate a signed upload URL", async () => {
98
97
  const bucket = "foo"
99
98
  const key = "bar"
@@ -108,7 +107,7 @@ describe("/static", () => {
108
107
  `https://${bucket}.s3.eu-west-1.amazonaws.com/${key}`
109
108
  )
110
109
  })
111
-
110
+
112
111
  it("should handle an invalid datasource ID", async () => {
113
112
  const res = await request
114
113
  .post(`/api/attachments/foo/url`)
@@ -123,7 +122,7 @@ describe("/static", () => {
123
122
  "The specified datasource could not be found"
124
123
  )
125
124
  })
126
-
125
+
127
126
  it("should require a bucket parameter", async () => {
128
127
  const res = await request
129
128
  .post(`/api/attachments/${datasource._id}/url`)
@@ -136,7 +135,7 @@ describe("/static", () => {
136
135
  .expect(400)
137
136
  expect(res.body.message).toEqual("bucket and key values are required")
138
137
  })
139
-
138
+
140
139
  it("should require a key parameter", async () => {
141
140
  const res = await request
142
141
  .post(`/api/attachments/${datasource._id}/url`)
@@ -151,4 +150,17 @@ describe("/static", () => {
151
150
  })
152
151
  })
153
152
 
153
+ describe("/preview", () => {
154
+ beforeEach(() => {
155
+ jest.clearAllMocks()
156
+ })
157
+
158
+ it("should serve the builder preview", async () => {
159
+ const headers = config.defaultHeaders()
160
+ const res = await request.get(`/preview`).set(headers).expect(200)
161
+
162
+ expect(res.body.appId).toBe(config.appId)
163
+ expect(res.body.builderPreview).toBe(true)
164
+ })
165
+ })
154
166
  })
package/src/app.ts CHANGED
@@ -83,9 +83,7 @@ server.on("close", async () => {
83
83
  return
84
84
  }
85
85
  shuttingDown = true
86
- if (!env.isTest()) {
87
- console.log("Server Closed")
88
- }
86
+ console.log("Server Closed")
89
87
  await automations.shutdown()
90
88
  await redis.shutdown()
91
89
  await events.shutdown()
@@ -167,3 +165,7 @@ process.on("uncaughtException", err => {
167
165
  process.on("SIGTERM", () => {
168
166
  shutdown()
169
167
  })
168
+
169
+ process.on("SIGINT", () => {
170
+ shutdown()
171
+ })
@@ -53,6 +53,7 @@ exports.shutdown = async () => {
53
53
  await automationQueue.close()
54
54
  automationQueue = null
55
55
  }
56
+ console.log("Bull shutdown")
56
57
  }
57
58
 
58
59
  exports.queue = automationQueue
@@ -23,6 +23,9 @@ 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
+ }
26
29
  const startDate = error.split(dbUtils.SEPARATOR)[2]
27
30
  if (startDate > maxStartDate) {
28
31
  updated.push(error)
@@ -0,0 +1,16 @@
1
+ import { QueryJson, Datasource } from "@budibase/types"
2
+ const { integrations } = require("../index")
3
+
4
+ export async function makeExternalQuery(
5
+ datasource: Datasource,
6
+ json: QueryJson
7
+ ) {
8
+ const Integration = integrations[datasource.source]
9
+ // query is the opinionated function
10
+ if (Integration.prototype.query) {
11
+ const integration = new Integration(datasource.config)
12
+ return integration.query(json)
13
+ } else {
14
+ throw "Datasource does not support query."
15
+ }
16
+ }
@@ -10,6 +10,7 @@ import { QueryOptions } from "../../definitions/datasource"
10
10
  import { isIsoDateString, SqlClient } from "../utils"
11
11
  import SqlTableQueryBuilder from "./sqlTable"
12
12
  import environment from "../../environment"
13
+ import { removeKeyNumbering } from "./utils"
13
14
 
14
15
  const envLimit = environment.SQL_MAX_ROWS
15
16
  ? parseInt(environment.SQL_MAX_ROWS)
@@ -133,12 +134,13 @@ class InternalBuilder {
133
134
  fn: (key: string, value: any) => void
134
135
  ) {
135
136
  for (let [key, value] of Object.entries(structure)) {
136
- const isRelationshipField = key.includes(".")
137
+ const updatedKey = removeKeyNumbering(key)
138
+ const isRelationshipField = updatedKey.includes(".")
137
139
  if (!opts.relationship && !isRelationshipField) {
138
- fn(`${opts.tableName}.${key}`, value)
140
+ fn(`${opts.tableName}.${updatedKey}`, value)
139
141
  }
140
142
  if (opts.relationship && isRelationshipField) {
141
- fn(key, value)
143
+ fn(updatedKey, value)
142
144
  }
143
145
  }
144
146
  }
@@ -157,6 +159,61 @@ class InternalBuilder {
157
159
  }
158
160
  }
159
161
 
162
+ const contains = (mode: object, any: boolean = false) => {
163
+ const fnc = allOr ? "orWhere" : "where"
164
+ const rawFnc = `${fnc}Raw`
165
+ const not = mode === filters?.notContains ? "NOT " : ""
166
+ function stringifyArray(value: Array<any>, quoteStyle = '"'): string {
167
+ for (let i in value) {
168
+ if (typeof value[i] === "string") {
169
+ value[i] = `${quoteStyle}${value[i]}${quoteStyle}`
170
+ }
171
+ }
172
+ return `[${value.join(",")}]`
173
+ }
174
+ if (this.client === SqlClient.POSTGRES) {
175
+ iterate(mode, (key: string, value: Array<any>) => {
176
+ const wrap = any ? "" : "'"
177
+ const containsOp = any ? "\\?| array" : "@>"
178
+ const fieldNames = key.split(/\./g)
179
+ const tableName = fieldNames[0]
180
+ const columnName = fieldNames[1]
181
+ // @ts-ignore
182
+ query = query[rawFnc](
183
+ `${not}"${tableName}"."${columnName}"::jsonb ${containsOp} ${wrap}${stringifyArray(
184
+ value,
185
+ any ? "'" : '"'
186
+ )}${wrap}`
187
+ )
188
+ })
189
+ } else if (this.client === SqlClient.MY_SQL) {
190
+ const jsonFnc = any ? "JSON_OVERLAPS" : "JSON_CONTAINS"
191
+ iterate(mode, (key: string, value: Array<any>) => {
192
+ // @ts-ignore
193
+ query = query[rawFnc](
194
+ `${not}${jsonFnc}(${key}, '${stringifyArray(value)}')`
195
+ )
196
+ })
197
+ } else {
198
+ const andOr = mode === filters?.containsAny ? " OR " : " AND "
199
+ iterate(mode, (key: string, value: Array<any>) => {
200
+ let statement = ""
201
+ for (let i in value) {
202
+ if (typeof value[i] === "string") {
203
+ value[i] = `%"${value[i]}"%`
204
+ } else {
205
+ value[i] = `%${value[i]}%`
206
+ }
207
+ statement +=
208
+ (statement ? andOr : "") +
209
+ `LOWER(${likeKey(this.client, key)}) LIKE ?`
210
+ }
211
+ // @ts-ignore
212
+ query = query[rawFnc](`${not}(${statement})`, value)
213
+ })
214
+ }
215
+ }
216
+
160
217
  if (!filters) {
161
218
  return query
162
219
  }
@@ -227,32 +284,13 @@ class InternalBuilder {
227
284
  })
228
285
  }
229
286
  if (filters.contains) {
230
- const fnc = allOr ? "orWhere" : "where"
231
- const rawFnc = `${fnc}Raw`
232
- if (this.client === SqlClient.POSTGRES) {
233
- iterate(filters.contains, (key: string, value: any) => {
234
- const fieldNames = key.split(/\./g)
235
- const tableName = fieldNames[0]
236
- const columnName = fieldNames[1]
237
- if (typeof value === "string") {
238
- value = `"${value}"`
239
- }
240
- // @ts-ignore
241
- query = query[rawFnc](
242
- `"${tableName}"."${columnName}"::jsonb @> '[${value}]'`
243
- )
244
- })
245
- } else if (this.client === SqlClient.MY_SQL) {
246
- iterate(filters.contains, (key: string, value: any) => {
247
- if (typeof value === "string") {
248
- value = `"${value}"`
249
- }
250
- // @ts-ignore
251
- query = query[rawFnc](`JSON_CONTAINS(${key}, '${value}')`)
252
- })
253
- } else {
254
- iterate(filters.contains, like)
255
- }
287
+ contains(filters.contains)
288
+ }
289
+ if (filters.notContains) {
290
+ contains(filters.notContains)
291
+ }
292
+ if (filters.containsAny) {
293
+ contains(filters.containsAny, true)
256
294
  }
257
295
  return query
258
296
  }
@@ -582,4 +620,3 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
582
620
  }
583
621
 
584
622
  export default SqlQueryBuilder
585
- module.exports = SqlQueryBuilder
@@ -1,21 +1,12 @@
1
- import { QueryJson, Datasource } from "@budibase/types"
1
+ const QUERY_START_REGEX = /\d[0-9]*:/g
2
2
 
3
- module DatasourceUtils {
4
- const { integrations } = require("../index")
5
-
6
- export async function makeExternalQuery(
7
- datasource: Datasource,
8
- json: QueryJson
9
- ) {
10
- const Integration = integrations[datasource.source]
11
- // query is the opinionated function
12
- if (Integration.prototype.query) {
13
- const integration = new Integration(datasource.config)
14
- return integration.query(json)
15
- } else {
16
- throw "Datasource does not support query."
17
- }
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
18
11
  }
19
-
20
- module.exports.makeExternalQuery = makeExternalQuery
21
12
  }
@@ -16,10 +16,10 @@ import {
16
16
  finaliseExternalTables,
17
17
  SqlClient,
18
18
  } from "./utils"
19
+ import Sql from "./base/sql"
19
20
 
20
21
  module MSSQLModule {
21
22
  const sqlServer = require("mssql")
22
- const Sql = require("./base/sql")
23
23
  const DEFAULT_SCHEMA = "dbo"
24
24
 
25
25
  interface MSSQLConfig {
@@ -97,7 +97,8 @@ module MSSQLModule {
97
97
  class SqlServerIntegration extends Sql implements DatasourcePlus {
98
98
  private readonly config: MSSQLConfig
99
99
  private index: number = 0
100
- static pool: any
100
+ private readonly pool: any
101
+ private client: any
101
102
  public tables: Record<string, Table> = {}
102
103
  public schemaErrors: Record<string, string> = {}
103
104
 
@@ -92,12 +92,15 @@ module MongoDBModule {
92
92
  if (json[field] instanceof Object) {
93
93
  json[field] = self.createObjectIds(json[field])
94
94
  }
95
- if (field === "_id" && typeof json[field] === "string") {
96
- const id = json["_id"].match(
95
+ if (
96
+ typeof json[field] === "string" &&
97
+ json[field].toLowerCase().startsWith("objectid")
98
+ ) {
99
+ const id = json[field].match(
97
100
  /(?<=objectid\(['"]).*(?=['"]\))/gi
98
101
  )?.[0]
99
102
  if (id) {
100
- json["_id"] = ObjectID.createFromHexString(id)
103
+ json[field] = ObjectID.createFromHexString(id)
101
104
  }
102
105
  }
103
106
  }
@@ -114,10 +117,31 @@ module MongoDBModule {
114
117
  }
115
118
 
116
119
  parseQueryParams(params: string, mode: string) {
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]) : {}
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] ?? {}
121
145
  if (mode === "update") {
122
146
  return {
123
147
  filter: group1,
@@ -176,7 +200,10 @@ module MongoDBModule {
176
200
  return await collection.findOne(json)
177
201
  }
178
202
  case "findOneAndUpdate": {
179
- let findAndUpdateJson = json as {
203
+ if (typeof query.json === "string") {
204
+ json = this.parseQueryParams(query.json, "update")
205
+ }
206
+ let findAndUpdateJson = this.createObjectIds(json) as {
180
207
  filter: FilterQuery<any>
181
208
  update: UpdateQuery<any>
182
209
  options: FindOneAndUpdateOption<any>
@@ -17,10 +17,10 @@ import {
17
17
  } from "./utils"
18
18
  import dayjs from "dayjs"
19
19
  const { NUMBER_REGEX } = require("../utilities")
20
+ import Sql from "./base/sql"
20
21
 
21
22
  module MySQLModule {
22
23
  const mysql = require("mysql2/promise")
23
- const Sql = require("./base/sql")
24
24
 
25
25
  interface MySQLConfig {
26
26
  host: string
@@ -14,10 +14,10 @@ import {
14
14
  finaliseExternalTables,
15
15
  SqlClient,
16
16
  } from "./utils"
17
+ import Sql from "./base/sql"
17
18
 
18
19
  module PostgresModule {
19
20
  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,6 +117,7 @@ module PostgresModule {
117
117
  private readonly client: any
118
118
  private readonly config: PostgresConfig
119
119
  private index: number = 1
120
+ private open: boolean
120
121
  public tables: Record<string, Table> = {}
121
122
  public schemaErrors: Record<string, string> = {}
122
123