@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.
- package/__mocks__/mongodb.ts +4 -0
- package/__mocks__/node-fetch.ts +8 -1
- package/builder/assets/index.00650f14.js +875 -0
- package/builder/assets/index.e50bda9f.css +6 -0
- package/builder/assets/{vendor.6bcafa60.js → vendor.67dbd8fa.js} +1 -1
- package/builder/index.html +3 -3
- package/coverage/clover.xml +549 -524
- package/coverage/coverage-final.json +20 -20
- package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
- package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
- package/coverage/lcov-report/api/controllers/component.js.html +1 -1
- package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +1 -1
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.html +1 -1
- package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/role.js.html +1 -1
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/index.html +25 -25
- package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +317 -191
- package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +27 -18
- package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
- package/coverage/lcov-report/api/controllers/script.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/external.js.html +2 -2
- package/coverage/lcov-report/api/controllers/table/index.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +19 -19
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
- package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +5 -5
- package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
- package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/routes/auth.js.html +1 -1
- package/coverage/lcov-report/api/routes/automation.js.html +1 -1
- package/coverage/lcov-report/api/routes/backup.js.html +1 -1
- package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
- package/coverage/lcov-report/api/routes/component.js.html +1 -1
- package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
- package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
- package/coverage/lcov-report/api/routes/dev.js.html +1 -1
- package/coverage/lcov-report/api/routes/index.html +1 -1
- package/coverage/lcov-report/api/routes/integration.js.html +1 -1
- package/coverage/lcov-report/api/routes/layout.js.html +1 -1
- package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
- package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
- package/coverage/lcov-report/api/routes/permission.js.html +1 -1
- package/coverage/lcov-report/api/routes/query.js.html +1 -1
- package/coverage/lcov-report/api/routes/role.js.html +1 -1
- package/coverage/lcov-report/api/routes/routing.js.html +1 -1
- package/coverage/lcov-report/api/routes/screen.js.html +1 -1
- package/coverage/lcov-report/api/routes/script.js.html +1 -1
- package/coverage/lcov-report/api/routes/table.js.html +1 -1
- package/coverage/lcov-report/api/routes/templates.js.html +1 -1
- package/coverage/lcov-report/api/routes/user.js.html +1 -1
- package/coverage/lcov-report/api/routes/utils/index.html +1 -1
- package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
- package/coverage/lcov-report/api/routes/view.js.html +1 -1
- package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/actions.js.html +1 -1
- package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
- package/coverage/lcov-report/automations/bullboard.js.html +9 -6
- package/coverage/lcov-report/automations/index.html +11 -11
- package/coverage/lcov-report/automations/index.js.html +1 -1
- package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
- package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
- package/coverage/lcov-report/automations/steps/index.html +1 -1
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
- package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
- package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
- package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
- package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/triggers.js.html +1 -1
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +30 -30
- package/coverage/lcov-report/constants/layouts.js.html +1 -1
- package/coverage/lcov-report/constants/screens.js.html +1 -1
- package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +1 -1
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
- package/coverage/lcov-report/db/newid.js.html +4 -4
- package/coverage/lcov-report/db/utils.js.html +73 -73
- package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
- package/coverage/lcov-report/events/index.html +1 -1
- package/coverage/lcov-report/events/index.js.html +1 -1
- package/coverage/lcov-report/events/utils.js.html +1 -1
- package/coverage/lcov-report/index.html +33 -33
- package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
- package/coverage/lcov-report/integrations/tests/index.html +1 -1
- package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
- package/coverage/lcov-report/middleware/builder.js.html +12 -12
- package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
- package/coverage/lcov-report/middleware/index.html +10 -10
- package/coverage/lcov-report/middleware/joi-validator.js.html +18 -9
- package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
- package/coverage/lcov-report/middleware/resourceId.js.html +12 -12
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +2 -2
- package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
- package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
- package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
- package/coverage/lcov-report/utilities/global.js.html +31 -31
- package/coverage/lcov-report/utilities/index.html +1 -1
- package/coverage/lcov-report/utilities/index.js.html +24 -24
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
- package/coverage/lcov-report/utilities/queue/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
- package/coverage/lcov-report/utilities/security.js.html +2 -2
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/rows.js.html +20 -20
- package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +7 -7
- package/coverage/lcov-report/utilities/workerRequests.js.html +13 -13
- package/coverage/lcov.info +888 -844
- package/dist/api/controllers/application.js +80 -14
- package/dist/api/controllers/row/internalSearch.js +39 -4
- package/dist/api/controllers/row/utils.js +3 -1
- package/dist/api/controllers/static/index.js +26 -2
- package/dist/api/controllers/static/templates/preview.hbs +103 -0
- package/dist/api/controllers/table/external.js +1 -1
- package/dist/api/routes/static.js +3 -0
- package/dist/app.js +4 -3
- package/dist/automations/bullboard.js +1 -0
- package/dist/automations/logging/index.js +3 -0
- package/dist/integrations/base/query.js +27 -0
- package/dist/integrations/base/sql.js +62 -30
- package/dist/integrations/base/utils.js +13 -27
- package/dist/integrations/microsoftSqlServer.js +5 -2
- package/dist/integrations/mongodb.js +35 -8
- package/dist/integrations/mysql.js +2 -2
- package/dist/integrations/postgres.js +5 -2
- package/dist/middleware/joi-validator.js +7 -4
- package/dist/package.json +7 -7
- package/dist/threads/index.js +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utilities/fileSystem/index.js +2 -1
- package/dist/utilities/redis.js +1 -0
- package/package.json +8 -8
- package/src/api/controllers/application.ts +96 -15
- package/src/api/controllers/row/internalSearch.js +45 -3
- package/src/api/controllers/row/utils.js +4 -1
- package/src/api/controllers/static/index.ts +21 -1
- package/src/api/controllers/static/templates/preview.hbs +103 -0
- package/src/api/controllers/table/external.js +1 -1
- package/src/api/routes/static.ts +12 -0
- package/src/api/routes/tests/application.spec.js +26 -0
- package/src/api/routes/tests/data/old-app.txt +3 -0
- package/src/api/routes/tests/internalSearch.spec.js +176 -0
- package/src/api/routes/tests/static.spec.js +19 -7
- package/src/app.ts +5 -3
- package/src/automations/bullboard.js +1 -0
- package/src/automations/logging/index.ts +3 -0
- package/src/integrations/base/query.ts +16 -0
- package/src/integrations/base/sql.ts +67 -30
- package/src/integrations/base/utils.ts +9 -18
- package/src/integrations/microsoftSqlServer.ts +3 -2
- package/src/integrations/mongodb.ts +35 -8
- package/src/integrations/mysql.ts +1 -1
- package/src/integrations/postgres.ts +2 -1
- package/src/integrations/tests/mongo.spec.js +218 -0
- package/src/integrations/tests/sql.spec.js +101 -11
- package/src/middleware/joi-validator.js +7 -4
- package/src/threads/index.ts +1 -0
- package/src/utilities/fileSystem/index.js +2 -0
- package/src/utilities/redis.js +1 -0
- package/builder/assets/index.08dd0c5e.css +0 -6
- 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
|
-
|
|
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
|
+
})
|
|
@@ -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
|
|
137
|
+
const updatedKey = removeKeyNumbering(key)
|
|
138
|
+
const isRelationshipField = updatedKey.includes(".")
|
|
137
139
|
if (!opts.relationship && !isRelationshipField) {
|
|
138
|
-
fn(`${opts.tableName}.${
|
|
140
|
+
fn(`${opts.tableName}.${updatedKey}`, value)
|
|
139
141
|
}
|
|
140
142
|
if (opts.relationship && isRelationshipField) {
|
|
141
|
-
fn(
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
1
|
+
const QUERY_START_REGEX = /\d[0-9]*:/g
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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 (
|
|
96
|
-
|
|
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[
|
|
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 =
|
|
118
|
-
let
|
|
119
|
-
let
|
|
120
|
-
let
|
|
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
|
-
|
|
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
|
|