@budibase/server 1.0.112 → 1.0.115
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/builder/assets/{index.e640c425.js → index.dae9f8cf.js} +4 -4
- package/builder/index.html +1 -1
- package/coverage/clover.xml +105 -150
- package/coverage/coverage-final.json +2 -2
- package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
- package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/controllers/application.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/index.js.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 +1 -1
- package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
- 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 +1 -1
- 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/table/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +1 -1
- 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 +1 -1
- 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/application.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/index.js.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/row.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/static.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 +1 -1
- package/coverage/lcov-report/automations/index.html +1 -1
- 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/createRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/deleteRow.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/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/automations/utils.js.html +1 -1
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +1 -1
- 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/client.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 +1 -1
- package/coverage/lcov-report/db/utils.js.html +1 -1
- 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 +20 -20
- 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/authorized.js.html +1 -1
- package/coverage/lcov-report/middleware/builder.js.html +1 -1
- package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
- package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
- package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +1 -1
- package/coverage/lcov-report/threads/automation.js.html +1 -1
- package/coverage/lcov-report/threads/index.html +29 -29
- package/coverage/lcov-report/threads/index.js.html +27 -9
- package/coverage/lcov-report/threads/query.js.html +20 -356
- package/coverage/lcov-report/threads/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
- 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 +1 -1
- package/coverage/lcov-report/utilities/index.html +1 -1
- package/coverage/lcov-report/utilities/index.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
- 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 +1 -1
- 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/index.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +1 -1
- package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
- package/coverage/lcov.info +185 -263
- package/dist/integrations/dynamodb.js +2 -1
- package/dist/integrations/queries/sql.js +108 -0
- package/dist/package.json +4 -4
- package/dist/threads/index.js +6 -1
- package/dist/threads/query.js +4 -103
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/scripts/integrations/mysql/init.sql +1 -0
- package/src/integrations/dynamodb.ts +2 -1
- package/src/integrations/queries/sql.ts +125 -0
- package/src/threads/index.js +7 -1
- package/src/threads/query.js +7 -119
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.115",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
"license": "GPL-3.0",
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"@apidevtools/swagger-parser": "^10.0.3",
|
|
71
|
-
"@budibase/backend-core": "^1.0.
|
|
72
|
-
"@budibase/client": "^1.0.
|
|
73
|
-
"@budibase/string-templates": "^1.0.
|
|
71
|
+
"@budibase/backend-core": "^1.0.115",
|
|
72
|
+
"@budibase/client": "^1.0.115",
|
|
73
|
+
"@budibase/string-templates": "^1.0.115",
|
|
74
74
|
"@bull-board/api": "^3.7.0",
|
|
75
75
|
"@bull-board/koa": "^3.7.0",
|
|
76
76
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -174,5 +174,5 @@
|
|
|
174
174
|
"optionalDependencies": {
|
|
175
175
|
"oracledb": "^5.3.0"
|
|
176
176
|
},
|
|
177
|
-
"gitHead": "
|
|
177
|
+
"gitHead": "732a547c2cc3940ecfe144433105960ca94423c8"
|
|
178
178
|
}
|
|
@@ -26,6 +26,7 @@ CREATE TABLE Products (
|
|
|
26
26
|
updated time
|
|
27
27
|
);
|
|
28
28
|
INSERT INTO Persons (FirstName, LastName, Age, Address, City, CreatedAt) VALUES ('Mike', 'Hughes', 28.2, '123 Fake Street', 'Belfast', '2021-01-19 03:14:07');
|
|
29
|
+
INSERT INTO Persons (FirstName, LastName, Age, Address, City, CreatedAt) VALUES ('Dave', 'Johnson', 29, '124 Fake Street', 'Belfast', '2022-04-01 00:11:11');
|
|
29
30
|
INSERT INTO Tasks (PersonID, TaskName, CreatedAt) VALUES (1, 'assembling', '2020-01-01');
|
|
30
31
|
INSERT INTO Tasks (PersonID, TaskName, CreatedAt) VALUES (2, 'processing', '2019-12-31');
|
|
31
32
|
INSERT INTO Products (name, updated) VALUES ('Meat', '11:00:22'), ('Fruit', '10:00:00');
|
|
@@ -131,11 +131,12 @@ module DynamoModule {
|
|
|
131
131
|
|
|
132
132
|
constructor(config: DynamoDBConfig) {
|
|
133
133
|
this.config = config
|
|
134
|
-
if (!this.config.endpoint) {
|
|
134
|
+
if (this.config.endpoint && !this.config.endpoint.includes("localhost")) {
|
|
135
135
|
this.connect()
|
|
136
136
|
}
|
|
137
137
|
let options = {
|
|
138
138
|
correctClockSkew: true,
|
|
139
|
+
region: this.config.region || AWS_REGION,
|
|
139
140
|
endpoint: config.endpoint ? config.endpoint : undefined,
|
|
140
141
|
}
|
|
141
142
|
this.client = new AWS.DynamoDB.DocumentClient(options)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { findHBSBlocks, processStringSync } from "@budibase/string-templates"
|
|
2
|
+
import { Integration } from "../../definitions/datasource"
|
|
3
|
+
import { DatasourcePlus } from "../base/datasourcePlus"
|
|
4
|
+
|
|
5
|
+
const CONST_CHAR_REGEX = new RegExp("'[^']*'", "g")
|
|
6
|
+
|
|
7
|
+
export function enrichQueryFields(
|
|
8
|
+
fields: { [key: string]: any },
|
|
9
|
+
parameters = {}
|
|
10
|
+
) {
|
|
11
|
+
const enrichedQuery: { [key: string]: any } = Array.isArray(fields) ? [] : {}
|
|
12
|
+
|
|
13
|
+
// enrich the fields with dynamic parameters
|
|
14
|
+
for (let key of Object.keys(fields)) {
|
|
15
|
+
if (fields[key] == null) {
|
|
16
|
+
continue
|
|
17
|
+
}
|
|
18
|
+
if (typeof fields[key] === "object") {
|
|
19
|
+
// enrich nested fields object
|
|
20
|
+
enrichedQuery[key] = enrichQueryFields(fields[key], parameters)
|
|
21
|
+
} else if (typeof fields[key] === "string") {
|
|
22
|
+
// enrich string value as normal
|
|
23
|
+
enrichedQuery[key] = processStringSync(fields[key], parameters, {
|
|
24
|
+
noEscaping: true,
|
|
25
|
+
noHelpers: true,
|
|
26
|
+
escapeNewlines: true,
|
|
27
|
+
})
|
|
28
|
+
} else {
|
|
29
|
+
enrichedQuery[key] = fields[key]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (
|
|
33
|
+
enrichedQuery.json ||
|
|
34
|
+
enrichedQuery.customData ||
|
|
35
|
+
enrichedQuery.requestBody
|
|
36
|
+
) {
|
|
37
|
+
try {
|
|
38
|
+
enrichedQuery.json = JSON.parse(
|
|
39
|
+
enrichedQuery.json ||
|
|
40
|
+
enrichedQuery.customData ||
|
|
41
|
+
enrichedQuery.requestBody
|
|
42
|
+
)
|
|
43
|
+
} catch (err) {
|
|
44
|
+
// no json found, ignore
|
|
45
|
+
}
|
|
46
|
+
delete enrichedQuery.customData
|
|
47
|
+
}
|
|
48
|
+
return enrichedQuery
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function interpolateSQL(
|
|
52
|
+
fields: { [key: string]: any },
|
|
53
|
+
parameters: { [key: string]: any },
|
|
54
|
+
integration: DatasourcePlus
|
|
55
|
+
) {
|
|
56
|
+
let sql = fields.sql
|
|
57
|
+
if (!sql || typeof sql !== "string") {
|
|
58
|
+
return fields
|
|
59
|
+
}
|
|
60
|
+
const bindings = findHBSBlocks(sql)
|
|
61
|
+
let variables = [],
|
|
62
|
+
arrays = []
|
|
63
|
+
for (let binding of bindings) {
|
|
64
|
+
// look for array/list operations in the SQL statement, which will need handled later
|
|
65
|
+
const listRegexMatch = sql.match(
|
|
66
|
+
new RegExp(`(in|IN|In|iN)( )+[(]?${binding}[)]?`)
|
|
67
|
+
)
|
|
68
|
+
// check if the variable was used as part of a string concat e.g. 'Hello {{binding}}'
|
|
69
|
+
// start by finding all the instances of const character strings
|
|
70
|
+
const charConstMatch = sql.match(CONST_CHAR_REGEX) || []
|
|
71
|
+
// now look within them to see if a binding is used
|
|
72
|
+
const charConstBindingMatch = charConstMatch.find((string: any) =>
|
|
73
|
+
string.match(new RegExp(`'[^']*${binding}[^']*'`))
|
|
74
|
+
)
|
|
75
|
+
if (charConstBindingMatch) {
|
|
76
|
+
let [part1, part2] = charConstBindingMatch.split(binding)
|
|
77
|
+
part1 = `'${part1.substring(1)}'`
|
|
78
|
+
part2 = `'${part2.substring(0, part2.length - 1)}'`
|
|
79
|
+
sql = sql.replace(
|
|
80
|
+
charConstBindingMatch,
|
|
81
|
+
integration.getStringConcat([
|
|
82
|
+
part1,
|
|
83
|
+
integration.getBindingIdentifier(),
|
|
84
|
+
part2,
|
|
85
|
+
])
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
// generate SQL parameterised array
|
|
89
|
+
else if (listRegexMatch) {
|
|
90
|
+
arrays.push(binding)
|
|
91
|
+
// determine the length of the array
|
|
92
|
+
const value = enrichQueryFields([binding], parameters)[0]
|
|
93
|
+
.split(",")
|
|
94
|
+
.map((val: string) => val.trim())
|
|
95
|
+
// build a string like ($1, $2, $3)
|
|
96
|
+
let replacement = `${Array.apply(null, Array(value.length))
|
|
97
|
+
.map(() => integration.getBindingIdentifier())
|
|
98
|
+
.join(",")}`
|
|
99
|
+
// check if parentheses are needed
|
|
100
|
+
if (!listRegexMatch[0].includes(`(${binding})`)) {
|
|
101
|
+
replacement = `(${replacement})`
|
|
102
|
+
}
|
|
103
|
+
sql = sql.replace(binding, replacement)
|
|
104
|
+
} else {
|
|
105
|
+
sql = sql.replace(binding, integration.getBindingIdentifier())
|
|
106
|
+
}
|
|
107
|
+
variables.push(binding)
|
|
108
|
+
}
|
|
109
|
+
// replicate the knex structure
|
|
110
|
+
fields.sql = sql
|
|
111
|
+
fields.bindings = enrichQueryFields(variables, parameters)
|
|
112
|
+
// check for arrays in the data
|
|
113
|
+
let updated: string[] = []
|
|
114
|
+
for (let i = 0; i < variables.length; i++) {
|
|
115
|
+
if (arrays.includes(variables[i])) {
|
|
116
|
+
updated = updated.concat(
|
|
117
|
+
fields.bindings[i].split(",").map((val: string) => val.trim())
|
|
118
|
+
)
|
|
119
|
+
} else {
|
|
120
|
+
updated.push(fields.bindings[i])
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
fields.bindings = updated
|
|
124
|
+
return fields
|
|
125
|
+
}
|
package/src/threads/index.js
CHANGED
|
@@ -36,6 +36,7 @@ class Thread {
|
|
|
36
36
|
maxConcurrentWorkers: this.count,
|
|
37
37
|
}
|
|
38
38
|
if (opts.timeoutMs) {
|
|
39
|
+
this.timeoutMs = opts.timeoutMs
|
|
39
40
|
workerOpts.maxCallTime = opts.timeoutMs
|
|
40
41
|
}
|
|
41
42
|
this.workers = workerFarm(workerOpts, typeToFile(type))
|
|
@@ -43,6 +44,7 @@ class Thread {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
run(data) {
|
|
47
|
+
const timeoutMs = this.timeoutMs
|
|
46
48
|
return new Promise((resolve, reject) => {
|
|
47
49
|
let fncToCall
|
|
48
50
|
// if in test then don't use threading
|
|
@@ -52,7 +54,11 @@ class Thread {
|
|
|
52
54
|
fncToCall = this.workers
|
|
53
55
|
}
|
|
54
56
|
fncToCall(data, (err, response) => {
|
|
55
|
-
if (err) {
|
|
57
|
+
if (err && err.type === "TimeoutError") {
|
|
58
|
+
reject(
|
|
59
|
+
new Error(`Query response time exceeded ${timeoutMs}ms timeout.`)
|
|
60
|
+
)
|
|
61
|
+
} else if (err) {
|
|
56
62
|
reject(err)
|
|
57
63
|
} else {
|
|
58
64
|
resolve(response)
|
package/src/threads/query.js
CHANGED
|
@@ -2,14 +2,13 @@ const threadUtils = require("./utils")
|
|
|
2
2
|
threadUtils.threadSetup()
|
|
3
3
|
const ScriptRunner = require("../utilities/scriptRunner")
|
|
4
4
|
const { integrations } = require("../integrations")
|
|
5
|
-
const {
|
|
6
|
-
processStringSync,
|
|
7
|
-
findHBSBlocks,
|
|
8
|
-
} = require("@budibase/string-templates")
|
|
5
|
+
const { processStringSync } = require("@budibase/string-templates")
|
|
9
6
|
const { doInAppContext, getAppDB } = require("@budibase/backend-core/context")
|
|
10
7
|
const { isSQL } = require("../integrations/utils")
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const {
|
|
9
|
+
enrichQueryFields,
|
|
10
|
+
interpolateSQL,
|
|
11
|
+
} = require("../integrations/queries/sql")
|
|
13
12
|
|
|
14
13
|
class QueryRunner {
|
|
15
14
|
constructor(input, flags = { noRecursiveQuery: false }) {
|
|
@@ -29,76 +28,6 @@ class QueryRunner {
|
|
|
29
28
|
this.hasRerun = false
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
interpolateSQL(fields, parameters, integration) {
|
|
33
|
-
let sql = fields.sql
|
|
34
|
-
if (!sql) {
|
|
35
|
-
return fields
|
|
36
|
-
}
|
|
37
|
-
const bindings = findHBSBlocks(sql)
|
|
38
|
-
let variables = [],
|
|
39
|
-
arrays = []
|
|
40
|
-
for (let binding of bindings) {
|
|
41
|
-
// look for array/list operations in the SQL statement, which will need handled later
|
|
42
|
-
const listRegexMatch = sql.match(
|
|
43
|
-
new RegExp(`(in|IN|In|iN)( )+[(]?${binding}[)]?`)
|
|
44
|
-
)
|
|
45
|
-
// check if the variable was used as part of a string concat e.g. 'Hello {{binding}}'
|
|
46
|
-
// start by finding all the instances of const character strings
|
|
47
|
-
const charConstMatch = sql.match(CONST_CHAR_REGEX) || []
|
|
48
|
-
// now look within them to see if a binding is used
|
|
49
|
-
const charConstBindingMatch = charConstMatch.find(string =>
|
|
50
|
-
string.match(new RegExp(`'[^']*${binding}[^']*'`))
|
|
51
|
-
)
|
|
52
|
-
if (charConstBindingMatch) {
|
|
53
|
-
let [part1, part2] = charConstBindingMatch.split(binding)
|
|
54
|
-
part1 = `'${part1.substring(1)}'`
|
|
55
|
-
part2 = `'${part2.substring(0, part2.length - 1)}'`
|
|
56
|
-
sql = sql.replace(
|
|
57
|
-
charConstBindingMatch,
|
|
58
|
-
integration.getStringConcat([
|
|
59
|
-
part1,
|
|
60
|
-
integration.getBindingIdentifier(),
|
|
61
|
-
part2,
|
|
62
|
-
])
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
// generate SQL parameterised array
|
|
66
|
-
else if (listRegexMatch) {
|
|
67
|
-
arrays.push(binding)
|
|
68
|
-
// determine the length of the array
|
|
69
|
-
const value = this.enrichQueryFields([binding], parameters)[0].split(
|
|
70
|
-
","
|
|
71
|
-
)
|
|
72
|
-
// build a string like ($1, $2, $3)
|
|
73
|
-
let replacement = `${Array.apply(null, Array(value.length))
|
|
74
|
-
.map(() => integration.getBindingIdentifier())
|
|
75
|
-
.join(",")}`
|
|
76
|
-
// check if parentheses are needed
|
|
77
|
-
if (!listRegexMatch[0].includes(`(${binding})`)) {
|
|
78
|
-
replacement = `(${replacement})`
|
|
79
|
-
}
|
|
80
|
-
sql = sql.replace(binding, replacement)
|
|
81
|
-
} else {
|
|
82
|
-
sql = sql.replace(binding, integration.getBindingIdentifier())
|
|
83
|
-
}
|
|
84
|
-
variables.push(binding)
|
|
85
|
-
}
|
|
86
|
-
// replicate the knex structure
|
|
87
|
-
fields.sql = sql
|
|
88
|
-
fields.bindings = this.enrichQueryFields(variables, parameters)
|
|
89
|
-
// check for arrays in the data
|
|
90
|
-
let updated = []
|
|
91
|
-
for (let i = 0; i < variables.length; i++) {
|
|
92
|
-
if (arrays.includes(variables[i])) {
|
|
93
|
-
updated = updated.concat(fields.bindings[i].split(","))
|
|
94
|
-
} else {
|
|
95
|
-
updated.push(fields.bindings[i])
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
fields.bindings = updated
|
|
99
|
-
return fields
|
|
100
|
-
}
|
|
101
|
-
|
|
102
31
|
async execute() {
|
|
103
32
|
let { datasource, fields, queryVerb, transformer } = this
|
|
104
33
|
const Integration = integrations[datasource.source]
|
|
@@ -112,9 +41,9 @@ class QueryRunner {
|
|
|
112
41
|
let query
|
|
113
42
|
// handle SQL injections by interpolating the variables
|
|
114
43
|
if (isSQL(datasource)) {
|
|
115
|
-
query =
|
|
44
|
+
query = interpolateSQL(fields, parameters, integration)
|
|
116
45
|
} else {
|
|
117
|
-
query =
|
|
46
|
+
query = enrichQueryFields(fields, parameters)
|
|
118
47
|
}
|
|
119
48
|
|
|
120
49
|
// Add pagination values for REST queries
|
|
@@ -259,47 +188,6 @@ class QueryRunner {
|
|
|
259
188
|
}
|
|
260
189
|
return parameters
|
|
261
190
|
}
|
|
262
|
-
|
|
263
|
-
enrichQueryFields(fields, parameters = {}) {
|
|
264
|
-
const enrichedQuery = Array.isArray(fields) ? [] : {}
|
|
265
|
-
|
|
266
|
-
// enrich the fields with dynamic parameters
|
|
267
|
-
for (let key of Object.keys(fields)) {
|
|
268
|
-
if (fields[key] == null) {
|
|
269
|
-
continue
|
|
270
|
-
}
|
|
271
|
-
if (typeof fields[key] === "object") {
|
|
272
|
-
// enrich nested fields object
|
|
273
|
-
enrichedQuery[key] = this.enrichQueryFields(fields[key], parameters)
|
|
274
|
-
} else if (typeof fields[key] === "string") {
|
|
275
|
-
// enrich string value as normal
|
|
276
|
-
enrichedQuery[key] = processStringSync(fields[key], parameters, {
|
|
277
|
-
noEscaping: true,
|
|
278
|
-
noHelpers: true,
|
|
279
|
-
escapeNewlines: true,
|
|
280
|
-
})
|
|
281
|
-
} else {
|
|
282
|
-
enrichedQuery[key] = fields[key]
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
if (
|
|
286
|
-
enrichedQuery.json ||
|
|
287
|
-
enrichedQuery.customData ||
|
|
288
|
-
enrichedQuery.requestBody
|
|
289
|
-
) {
|
|
290
|
-
try {
|
|
291
|
-
enrichedQuery.json = JSON.parse(
|
|
292
|
-
enrichedQuery.json ||
|
|
293
|
-
enrichedQuery.customData ||
|
|
294
|
-
enrichedQuery.requestBody
|
|
295
|
-
)
|
|
296
|
-
} catch (err) {
|
|
297
|
-
// no json found, ignore
|
|
298
|
-
}
|
|
299
|
-
delete enrichedQuery.customData
|
|
300
|
-
}
|
|
301
|
-
return enrichedQuery
|
|
302
|
-
}
|
|
303
191
|
}
|
|
304
192
|
|
|
305
193
|
module.exports = (input, callback) => {
|