@budibase/server 0.9.186 → 0.9.190-alpha.0
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/Dockerfile +7 -1
- package/LICENSE +1 -1
- package/__mocks__/mssql.ts +1 -1
- package/__mocks__/oracledb.ts +31 -0
- package/__mocks__/pg.ts +3 -0
- package/builder/assets/bb-space-man.5be51a45.svg +290 -0
- package/builder/assets/index.43f4c913.js +1316 -0
- package/builder/assets/index.7d405e74.css +1 -0
- package/builder/assets/oracle.66592424.png +0 -0
- package/builder/assets/vendor.470042a4.js +152 -0
- package/builder/assets/vendor.5e1fe644.css +1 -0
- package/builder/index.html +4 -4
- package/coverage/clover.xml +1520 -1087
- package/coverage/coverage-final.json +93 -89
- package/coverage/lcov-report/api/controllers/analytics.js.html +2 -2
- package/coverage/lcov-report/api/controllers/apikeys.js.html +2 -2
- package/coverage/lcov-report/api/controllers/application.js.html +64 -13
- package/coverage/lcov-report/api/controllers/auth.js.html +19 -10
- package/coverage/lcov-report/api/controllers/automation.js.html +3 -3
- 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 +4 -4
- package/coverage/lcov-report/api/controllers/datasource.js.html +232 -28
- package/coverage/lcov-report/api/controllers/dev.js.html +16 -7
- package/coverage/lcov-report/api/controllers/hosting.js.html +10 -10
- package/coverage/lcov-report/api/controllers/index.html +91 -91
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +3 -3
- package/coverage/lcov-report/api/controllers/metadata.js.html +3 -3
- package/coverage/lcov-report/api/controllers/permission.js.html +3 -3
- package/coverage/lcov-report/api/controllers/query.js.html +53 -209
- package/coverage/lcov-report/api/controllers/role.js.html +9 -9
- package/coverage/lcov-report/api/controllers/routing.js.html +3 -3
- package/coverage/lcov-report/api/controllers/row/external.js.html +17 -8
- package/coverage/lcov-report/api/controllers/row/index.html +26 -26
- package/coverage/lcov-report/api/controllers/row/index.js.html +2 -2
- package/coverage/lcov-report/api/controllers/row/internal.js.html +9 -9
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +2 -2
- package/coverage/lcov-report/api/controllers/row/utils.js.html +21 -30
- package/coverage/lcov-report/api/controllers/screen.js.html +2 -2
- package/coverage/lcov-report/api/controllers/script.js.html +3 -3
- package/coverage/lcov-report/api/controllers/table/external.js.html +1001 -0
- package/coverage/lcov-report/api/controllers/table/index.html +56 -26
- package/coverage/lcov-report/api/controllers/table/index.js.html +80 -350
- package/coverage/lcov-report/api/controllers/table/internal.js.html +545 -0
- package/coverage/lcov-report/api/controllers/table/utils.js.html +175 -52
- package/coverage/lcov-report/api/controllers/templates.js.html +4 -4
- package/coverage/lcov-report/api/controllers/user.js.html +390 -33
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +19 -4
- package/coverage/lcov-report/api/controllers/view/index.html +22 -22
- package/coverage/lcov-report/api/controllers/view/index.js.html +52 -13
- package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +3 -3
- package/coverage/lcov-report/api/controllers/webhook.js.html +4 -4
- 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 +2 -2
- package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
- package/coverage/lcov-report/api/routes/index.html +4 -4
- 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/permission.js.html +1 -1
- package/coverage/lcov-report/api/routes/query.js.html +5 -2
- 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 +2 -2
- package/coverage/lcov-report/api/routes/table.js.html +35 -2
- package/coverage/lcov-report/api/routes/templates.js.html +1 -1
- package/coverage/lcov-report/api/routes/user.js.html +17 -2
- 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 +2 -2
- package/coverage/lcov-report/automations/automationUtils.js.html +4 -4
- package/coverage/lcov-report/automations/bullboard.js.html +71 -20
- package/coverage/lcov-report/automations/index.html +35 -50
- package/coverage/lcov-report/automations/index.js.html +2 -2
- 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 +3 -3
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeScript.js.html +3 -3
- package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
- package/coverage/lcov-report/automations/steps/index.html +14 -14
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +3 -3
- package/coverage/lcov-report/automations/steps/queryRows.js.html +3 -3
- 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 +7 -7
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
- package/coverage/lcov-report/automations/triggers.js.html +22 -10
- package/coverage/lcov-report/automations/utils.js.html +42 -12
- package/coverage/lcov-report/constants/index.html +5 -5
- package/coverage/lcov-report/constants/index.js.html +87 -21
- 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 +2 -2
- package/coverage/lcov-report/db/inMemoryView.js.html +2 -2
- package/coverage/lcov-report/db/index.html +2 -2
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +6 -6
- package/coverage/lcov-report/db/linkedRows/index.html +10 -10
- package/coverage/lcov-report/db/linkedRows/index.js.html +5 -5
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +6 -6
- package/coverage/lcov-report/db/newid.js.html +3 -3
- package/coverage/lcov-report/db/utils.js.html +57 -57
- package/coverage/lcov-report/events/AutomationEmitter.js.html +6 -6
- package/coverage/lcov-report/events/index.html +6 -6
- package/coverage/lcov-report/events/index.js.html +1 -1
- package/coverage/lcov-report/events/utils.js.html +5 -5
- package/coverage/lcov-report/index.html +108 -93
- 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 +2 -2
- package/coverage/lcov-report/middleware/authorized.js.html +58 -34
- package/coverage/lcov-report/middleware/builder.js.html +16 -7
- package/coverage/lcov-report/middleware/currentapp.js.html +6 -6
- package/coverage/lcov-report/middleware/index.html +27 -27
- package/coverage/lcov-report/middleware/joi-validator.js.html +2 -2
- package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
- package/coverage/lcov-report/middleware/selfhost.js.html +2 -2
- package/coverage/lcov-report/middleware/usageQuota.js.html +4 -4
- package/coverage/lcov-report/middleware/utils.js.html +1 -1
- package/coverage/lcov-report/{automations/thread.js.html → threads/automation.js.html} +90 -33
- package/coverage/lcov-report/threads/index.html +141 -0
- package/coverage/lcov-report/threads/index.js.html +278 -0
- package/coverage/lcov-report/threads/query.js.html +278 -0
- 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 +144 -15
- package/coverage/lcov-report/utilities/global.js.html +26 -11
- package/coverage/lcov-report/utilities/index.html +48 -48
- package/coverage/lcov-report/utilities/index.js.html +47 -14
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +30 -9
- package/coverage/lcov-report/utilities/queue/index.html +14 -14
- 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 +4 -4
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +2 -2
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +3 -3
- package/coverage/lcov-report/utilities/scriptRunner.js.html +16 -7
- package/coverage/lcov-report/utilities/security.js.html +3 -3
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +1 -1
- package/coverage/lcov-report/utilities/workerRequests.js.html +5 -5
- package/coverage/lcov.info +2558 -1787
- package/dist/api/controllers/application.js +15 -1
- package/dist/api/controllers/auth.js +3 -3
- package/dist/api/controllers/datasource.js +67 -16
- package/dist/api/controllers/deploy/index.js +2 -0
- package/dist/api/controllers/dev.js +4 -1
- package/dist/api/controllers/query.js +30 -58
- package/dist/api/controllers/row/ExternalRequest.js +37 -14
- package/dist/api/controllers/row/external.js +3 -1
- package/dist/api/controllers/row/utils.js +6 -12
- package/dist/api/controllers/table/external.js +249 -0
- package/dist/api/controllers/table/index.js +49 -123
- package/dist/api/controllers/table/internal.js +150 -0
- package/dist/api/controllers/table/utils.js +62 -28
- package/dist/api/controllers/user.js +123 -11
- package/dist/api/controllers/view/exporters.js +4 -0
- package/dist/api/controllers/view/index.js +14 -2
- package/dist/api/routes/query.js +1 -1
- package/dist/api/routes/table.js +7 -1
- package/dist/api/routes/user.js +2 -1
- package/dist/app.js +2 -11
- package/dist/automations/bullboard.js +37 -10
- package/dist/automations/triggers.js +7 -3
- package/dist/automations/utils.js +11 -2
- package/dist/constants/index.js +19 -0
- package/dist/definitions/datasource.js +5 -0
- package/dist/environment.js +13 -0
- package/dist/integrations/base/IntegrationBase.js +2 -0
- package/dist/integrations/base/datasourcePlus.js +2 -0
- package/dist/integrations/base/sql.js +338 -180
- package/dist/integrations/base/sqlTable.js +143 -0
- package/dist/integrations/base/utils.js +30 -0
- package/dist/integrations/index.js +6 -0
- package/dist/integrations/microsoftSqlServer.js +117 -9
- package/dist/integrations/mysql.js +14 -84
- package/dist/integrations/oracle.js +345 -0
- package/dist/integrations/postgres.js +35 -28
- package/dist/integrations/utils.js +71 -9
- package/dist/middleware/authorized.js +22 -11
- package/dist/middleware/builder.js +4 -1
- package/dist/package.json +13 -8
- package/dist/tests/utilities/TestConfiguration.js +2 -1
- package/dist/{automations/thread.js → threads/automation.js} +26 -8
- package/dist/threads/index.js +64 -0
- package/dist/threads/query.js +64 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/csvParser.js +46 -5
- package/dist/utilities/global.js +6 -2
- package/dist/utilities/index.js +11 -0
- package/dist/utilities/queue/inMemoryQueue.js +8 -0
- package/dist/utilities/scriptRunner.js +4 -1
- package/package.json +14 -9
- package/scripts/dev/manage.js +1 -0
- package/scripts/integrations/mssql/data/Dockerfile +9 -0
- package/scripts/integrations/mssql/data/entrypoint.sh +24 -0
- package/scripts/integrations/mssql/data/setup.sql +54 -0
- package/scripts/integrations/mssql/docker-compose.yaml +12 -0
- package/scripts/integrations/mssql/reset.sh +3 -0
- package/scripts/integrations/oracle/docker-compose.yml +19 -0
- package/scripts/integrations/oracle/instantclient/linux/x86-64/basiclite-21.4.zip +0 -0
- package/scripts/integrations/oracle/instantclient/linux/x86-64/install.sh +23 -0
- package/scripts/integrations/oracle/oracle.md +90 -0
- package/scripts/integrations/postgres/docker-compose.yml +3 -3
- package/scripts/likeCypress.ts +33 -0
- package/src/api/controllers/application.js +18 -1
- package/src/api/controllers/auth.js +3 -0
- package/src/api/controllers/datasource.js +84 -16
- package/src/api/controllers/deploy/index.js +2 -0
- package/src/api/controllers/dev.js +4 -1
- package/src/api/controllers/query.js +29 -81
- package/src/api/controllers/row/ExternalRequest.ts +47 -16
- package/src/api/controllers/row/external.js +4 -1
- package/src/api/controllers/row/utils.js +8 -11
- package/src/api/controllers/table/external.js +307 -0
- package/src/api/controllers/table/index.js +47 -137
- package/src/api/controllers/table/internal.js +155 -0
- package/src/api/controllers/table/utils.js +74 -33
- package/src/api/controllers/user.js +132 -13
- package/src/api/controllers/view/exporters.js +5 -0
- package/src/api/controllers/view/index.js +15 -2
- package/src/api/routes/query.js +1 -0
- package/src/api/routes/table.js +11 -0
- package/src/api/routes/tests/datasource.spec.js +2 -2
- package/src/api/routes/tests/misc.spec.js +5 -1
- package/src/api/routes/tests/query.spec.js +0 -1
- package/src/api/routes/user.js +5 -0
- package/src/app.ts +2 -10
- package/src/automations/bullboard.js +28 -11
- package/src/automations/tests/automation.spec.js +3 -4
- package/src/automations/triggers.js +7 -3
- package/src/automations/utils.js +12 -2
- package/src/constants/index.js +22 -0
- package/src/definitions/common.ts +7 -1
- package/src/definitions/datasource.ts +10 -3
- package/src/environment.js +15 -0
- package/src/integrations/airtable.ts +2 -1
- package/src/integrations/arangodb.ts +2 -1
- package/src/integrations/base/IntegrationBase.ts +6 -0
- package/src/integrations/base/datasourcePlus.ts +9 -0
- package/src/integrations/base/sql.ts +362 -222
- package/src/integrations/base/sqlTable.ts +180 -0
- package/src/integrations/base/utils.ts +22 -0
- package/src/integrations/couchdb.ts +2 -1
- package/src/integrations/dynamodb.ts +2 -1
- package/src/integrations/elasticsearch.ts +2 -1
- package/src/integrations/index.ts +7 -0
- package/src/integrations/microsoftSqlServer.ts +145 -13
- package/src/integrations/mongodb.ts +2 -1
- package/src/integrations/mysql.ts +20 -94
- package/src/integrations/oracle.ts +445 -0
- package/src/integrations/postgres.ts +45 -35
- package/src/integrations/rest.ts +2 -1
- package/src/integrations/s3.ts +2 -1
- package/src/integrations/tests/microsoftSqlServer.spec.js +22 -15
- package/src/integrations/tests/oracle.spec.js +94 -0
- package/src/integrations/tests/postgres.spec.js +4 -0
- package/src/integrations/utils.ts +74 -8
- package/src/middleware/authorized.js +26 -18
- package/src/middleware/builder.js +4 -1
- package/src/middleware/tests/authorized.spec.js +2 -0
- package/src/tests/utilities/TestConfiguration.js +2 -1
- package/src/{automations/thread.js → threads/automation.js} +27 -8
- package/src/threads/index.js +66 -0
- package/src/threads/query.js +66 -0
- package/src/utilities/csvParser.js +48 -5
- package/src/utilities/global.js +7 -2
- package/src/utilities/index.js +11 -0
- package/src/utilities/queue/inMemoryQueue.js +7 -0
- package/src/utilities/scriptRunner.js +4 -1
- package/src/utilities/tests/__snapshots__/csvParser.spec.js.snap +0 -6
- package/src/utilities/tests/csvParser.spec.js +3 -0
- package/tsconfig.json +1 -1
- package/builder/assets/index.10556cc1.js +0 -201
- package/builder/assets/index.7469e1e4.css +0 -29
- package/builder/assets/vendor.278a305c.js +0 -9
- package/builder/assets/vendor.d75d5eb7.css +0 -1
|
@@ -7,8 +7,9 @@ const {
|
|
|
7
7
|
BudibaseInternalDB,
|
|
8
8
|
getTableParams,
|
|
9
9
|
} = require("../../db/utils")
|
|
10
|
+
const { BuildSchemaErrors, InvalidColumns } = require("../../constants")
|
|
10
11
|
const { integrations } = require("../../integrations")
|
|
11
|
-
const {
|
|
12
|
+
const { getDatasourceAndQuery } = require("./row/utils")
|
|
12
13
|
|
|
13
14
|
exports.fetch = async function (ctx) {
|
|
14
15
|
const database = new CouchDB(ctx.appId)
|
|
@@ -43,13 +44,17 @@ exports.buildSchemaFromDb = async function (ctx) {
|
|
|
43
44
|
const db = new CouchDB(ctx.appId)
|
|
44
45
|
const datasource = await db.get(ctx.params.datasourceId)
|
|
45
46
|
|
|
46
|
-
const tables = await buildSchemaHelper(datasource)
|
|
47
|
+
const { tables, error } = await buildSchemaHelper(datasource)
|
|
47
48
|
datasource.entities = tables
|
|
48
49
|
|
|
49
|
-
const
|
|
50
|
-
datasource._rev =
|
|
50
|
+
const dbResp = await db.put(datasource)
|
|
51
|
+
datasource._rev = dbResp.rev
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
const response = { datasource }
|
|
54
|
+
if (error) {
|
|
55
|
+
response.error = error
|
|
56
|
+
}
|
|
57
|
+
ctx.body = response
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
exports.update = async function (ctx) {
|
|
@@ -71,7 +76,7 @@ exports.update = async function (ctx) {
|
|
|
71
76
|
|
|
72
77
|
ctx.status = 200
|
|
73
78
|
ctx.message = "Datasource saved successfully."
|
|
74
|
-
ctx.body = datasource
|
|
79
|
+
ctx.body = { datasource }
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
exports.save = async function (ctx) {
|
|
@@ -85,13 +90,15 @@ exports.save = async function (ctx) {
|
|
|
85
90
|
...ctx.request.body.datasource,
|
|
86
91
|
}
|
|
87
92
|
|
|
93
|
+
let schemaError = null
|
|
88
94
|
if (fetchSchema) {
|
|
89
|
-
|
|
95
|
+
const { tables, error } = await buildSchemaHelper(datasource)
|
|
96
|
+
schemaError = error
|
|
90
97
|
datasource.entities = tables
|
|
91
98
|
}
|
|
92
99
|
|
|
93
|
-
const
|
|
94
|
-
datasource._rev =
|
|
100
|
+
const dbResp = await db.put(datasource)
|
|
101
|
+
datasource._rev = dbResp.rev
|
|
95
102
|
|
|
96
103
|
// Drain connection pools when configuration is changed
|
|
97
104
|
if (datasource.source) {
|
|
@@ -101,17 +108,27 @@ exports.save = async function (ctx) {
|
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
const response = { datasource }
|
|
112
|
+
if (schemaError) {
|
|
113
|
+
response.error = schemaError
|
|
114
|
+
}
|
|
115
|
+
ctx.body = response
|
|
107
116
|
}
|
|
108
117
|
|
|
109
118
|
exports.destroy = async function (ctx) {
|
|
110
119
|
const db = new CouchDB(ctx.appId)
|
|
111
120
|
|
|
112
121
|
// Delete all queries for the datasource
|
|
113
|
-
const
|
|
114
|
-
|
|
122
|
+
const queries = await db.allDocs(
|
|
123
|
+
getQueryParams(ctx.params.datasourceId, null)
|
|
124
|
+
)
|
|
125
|
+
await db.bulkDocs(
|
|
126
|
+
queries.rows.map(row => ({
|
|
127
|
+
_id: row.id,
|
|
128
|
+
_rev: row.value.rev,
|
|
129
|
+
_deleted: true,
|
|
130
|
+
}))
|
|
131
|
+
)
|
|
115
132
|
|
|
116
133
|
// delete the datasource
|
|
117
134
|
await db.remove(ctx.params.datasourceId, ctx.params.revId)
|
|
@@ -129,12 +146,29 @@ exports.find = async function (ctx) {
|
|
|
129
146
|
exports.query = async function (ctx) {
|
|
130
147
|
const queryJson = ctx.request.body
|
|
131
148
|
try {
|
|
132
|
-
ctx.body = await
|
|
149
|
+
ctx.body = await getDatasourceAndQuery(ctx.appId, queryJson)
|
|
133
150
|
} catch (err) {
|
|
134
151
|
ctx.throw(400, err)
|
|
135
152
|
}
|
|
136
153
|
}
|
|
137
154
|
|
|
155
|
+
function getErrorTables(errors, errorType) {
|
|
156
|
+
return Object.entries(errors)
|
|
157
|
+
.filter(entry => entry[1] === errorType)
|
|
158
|
+
.map(([name]) => name)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function updateError(error, newError, tables) {
|
|
162
|
+
if (!error) {
|
|
163
|
+
error = ""
|
|
164
|
+
}
|
|
165
|
+
if (error.length > 0) {
|
|
166
|
+
error += "\n"
|
|
167
|
+
}
|
|
168
|
+
error += `${newError} ${tables.join(", ")}`
|
|
169
|
+
return error
|
|
170
|
+
}
|
|
171
|
+
|
|
138
172
|
const buildSchemaHelper = async datasource => {
|
|
139
173
|
const Connector = integrations[datasource.source]
|
|
140
174
|
|
|
@@ -143,5 +177,39 @@ const buildSchemaHelper = async datasource => {
|
|
|
143
177
|
await connector.buildSchema(datasource._id, datasource.entities)
|
|
144
178
|
datasource.entities = connector.tables
|
|
145
179
|
|
|
146
|
-
|
|
180
|
+
// make sure they all have a display name selected
|
|
181
|
+
for (let entity of Object.values(datasource.entities)) {
|
|
182
|
+
if (entity.primaryDisplay) {
|
|
183
|
+
continue
|
|
184
|
+
}
|
|
185
|
+
const notAutoColumn = Object.values(entity.schema).find(
|
|
186
|
+
schema => !schema.autocolumn
|
|
187
|
+
)
|
|
188
|
+
if (notAutoColumn) {
|
|
189
|
+
entity.primaryDisplay = notAutoColumn.name
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const errors = connector.schemaErrors
|
|
194
|
+
let error = null
|
|
195
|
+
if (errors && Object.keys(errors).length > 0) {
|
|
196
|
+
const noKey = getErrorTables(errors, BuildSchemaErrors.NO_KEY)
|
|
197
|
+
const invalidCol = getErrorTables(errors, BuildSchemaErrors.INVALID_COLUMN)
|
|
198
|
+
if (noKey.length) {
|
|
199
|
+
error = updateError(
|
|
200
|
+
error,
|
|
201
|
+
"No primary key constraint found for the following:",
|
|
202
|
+
noKey
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
if (invalidCol.length) {
|
|
206
|
+
const invalidCols = Object.values(InvalidColumns).join(", ")
|
|
207
|
+
error = updateError(
|
|
208
|
+
error,
|
|
209
|
+
`Cannot use columns ${invalidCols} found in following:`,
|
|
210
|
+
invalidCol
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return { tables: connector.tables, error }
|
|
147
215
|
}
|
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
disableAllCrons,
|
|
7
7
|
enableCronTrigger,
|
|
8
8
|
} = require("../../../automations/utils")
|
|
9
|
+
const { app: appCache } = require("@budibase/auth/cache")
|
|
9
10
|
|
|
10
11
|
// the max time we can wait for an invalidation to complete before considering it failed
|
|
11
12
|
const MAX_PENDING_TIME_MS = 30 * 60000
|
|
@@ -103,6 +104,7 @@ async function deployApp(deployment) {
|
|
|
103
104
|
appDoc.appId = productionAppId
|
|
104
105
|
appDoc.instance._id = productionAppId
|
|
105
106
|
await db.put(appDoc)
|
|
107
|
+
await appCache.invalidateAppMetadata(productionAppId)
|
|
106
108
|
console.log("New app doc written successfully.")
|
|
107
109
|
await initDeployedApp(productionAppId)
|
|
108
110
|
console.log("Deployed app initialised, setting deployment to successful")
|
|
@@ -6,6 +6,7 @@ const { request } = require("../../utilities/workerRequests")
|
|
|
6
6
|
const { clearLock } = require("../../utilities/redis")
|
|
7
7
|
const { Replication } = require("@budibase/auth").db
|
|
8
8
|
const { DocumentTypes } = require("../../db/utils")
|
|
9
|
+
const { app: appCache } = require("@budibase/auth/cache")
|
|
9
10
|
|
|
10
11
|
async function redirect(ctx, method, path = "global") {
|
|
11
12
|
const { devPath } = ctx.params
|
|
@@ -24,7 +25,8 @@ async function redirect(ctx, method, path = "global") {
|
|
|
24
25
|
)
|
|
25
26
|
)
|
|
26
27
|
if (response.status !== 200) {
|
|
27
|
-
|
|
28
|
+
const err = await response.text()
|
|
29
|
+
ctx.throw(400, err)
|
|
28
30
|
}
|
|
29
31
|
const cookie = response.headers.get("set-cookie")
|
|
30
32
|
if (cookie) {
|
|
@@ -106,6 +108,7 @@ exports.revert = async ctx => {
|
|
|
106
108
|
appDoc.appId = appId
|
|
107
109
|
appDoc.instance._id = appId
|
|
108
110
|
await db.put(appDoc)
|
|
111
|
+
await appCache.invalidateAppMetadata(appId)
|
|
109
112
|
ctx.body = {
|
|
110
113
|
message: "Reverted changes successfully.",
|
|
111
114
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const { processString } = require("@budibase/string-templates")
|
|
2
2
|
const CouchDB = require("../../db")
|
|
3
3
|
const { generateQueryID, getQueryParams } = require("../../db/utils")
|
|
4
|
-
const { integrations } = require("../../integrations")
|
|
5
4
|
const { BaseQueryVerbs } = require("../../constants")
|
|
6
5
|
const env = require("../../environment")
|
|
7
|
-
const
|
|
6
|
+
const { Thread, ThreadType } = require("../../threads")
|
|
7
|
+
|
|
8
|
+
const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 })
|
|
8
9
|
|
|
9
10
|
// simple function to append "readable" to all read queries
|
|
10
11
|
function enrichQueries(input) {
|
|
@@ -18,47 +19,6 @@ function enrichQueries(input) {
|
|
|
18
19
|
return wasArray ? queries : queries[0]
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
function formatResponse(resp) {
|
|
22
|
-
if (typeof resp === "string") {
|
|
23
|
-
try {
|
|
24
|
-
resp = JSON.parse(resp)
|
|
25
|
-
} catch (err) {
|
|
26
|
-
resp = { response: resp }
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return resp
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async function runAndTransform(
|
|
33
|
-
integration,
|
|
34
|
-
queryVerb,
|
|
35
|
-
enrichedQuery,
|
|
36
|
-
transformer
|
|
37
|
-
) {
|
|
38
|
-
let rows = formatResponse(await integration[queryVerb](enrichedQuery))
|
|
39
|
-
|
|
40
|
-
// transform as required
|
|
41
|
-
if (transformer) {
|
|
42
|
-
const runner = new ScriptRunner(transformer, { data: rows })
|
|
43
|
-
rows = runner.execute()
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// needs to an array for next step
|
|
47
|
-
if (!Array.isArray(rows)) {
|
|
48
|
-
rows = [rows]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// map into JSON if just raw primitive here
|
|
52
|
-
if (rows.find(row => typeof row !== "object")) {
|
|
53
|
-
rows = rows.map(value => ({ value }))
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// get all the potential fields in the schema
|
|
57
|
-
let keys = rows.flatMap(Object.keys)
|
|
58
|
-
|
|
59
|
-
return { rows, keys }
|
|
60
|
-
}
|
|
61
|
-
|
|
62
22
|
exports.fetch = async function (ctx) {
|
|
63
23
|
const db = new CouchDB(ctx.appId)
|
|
64
24
|
|
|
@@ -98,7 +58,9 @@ async function enrichQueryFields(fields, parameters = {}) {
|
|
|
98
58
|
enrichedQuery[key] = await enrichQueryFields(fields[key], parameters)
|
|
99
59
|
} else if (typeof fields[key] === "string") {
|
|
100
60
|
// enrich string value as normal
|
|
101
|
-
enrichedQuery[key] = await processString(fields[key], parameters
|
|
61
|
+
enrichedQuery[key] = await processString(fields[key], parameters, {
|
|
62
|
+
noHelpers: true,
|
|
63
|
+
})
|
|
102
64
|
} else {
|
|
103
65
|
enrichedQuery[key] = fields[key]
|
|
104
66
|
}
|
|
@@ -141,30 +103,23 @@ exports.preview = async function (ctx) {
|
|
|
141
103
|
|
|
142
104
|
const datasource = await db.get(ctx.request.body.datasourceId)
|
|
143
105
|
|
|
144
|
-
const Integration = integrations[datasource.source]
|
|
145
|
-
|
|
146
|
-
if (!Integration) {
|
|
147
|
-
ctx.throw(400, "Integration type does not exist.")
|
|
148
|
-
}
|
|
149
|
-
|
|
150
106
|
const { fields, parameters, queryVerb, transformer } = ctx.request.body
|
|
151
107
|
const enrichedQuery = await enrichQueryFields(fields, parameters)
|
|
152
|
-
const integration = new Integration(datasource.config)
|
|
153
108
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
109
|
+
try {
|
|
110
|
+
const { rows, keys } = await Runner.run({
|
|
111
|
+
datasource,
|
|
112
|
+
queryVerb,
|
|
113
|
+
query: enrichedQuery,
|
|
114
|
+
transformer,
|
|
115
|
+
})
|
|
160
116
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
integration.end()
|
|
117
|
+
ctx.body = {
|
|
118
|
+
rows,
|
|
119
|
+
schemaFields: [...new Set(keys)],
|
|
120
|
+
}
|
|
121
|
+
} catch (err) {
|
|
122
|
+
ctx.throw(400, err)
|
|
168
123
|
}
|
|
169
124
|
}
|
|
170
125
|
|
|
@@ -174,29 +129,22 @@ exports.execute = async function (ctx) {
|
|
|
174
129
|
const query = await db.get(ctx.params.queryId)
|
|
175
130
|
const datasource = await db.get(query.datasourceId)
|
|
176
131
|
|
|
177
|
-
const Integration = integrations[datasource.source]
|
|
178
|
-
|
|
179
|
-
if (!Integration) {
|
|
180
|
-
ctx.throw(400, "Integration type does not exist.")
|
|
181
|
-
}
|
|
182
|
-
|
|
183
132
|
const enrichedQuery = await enrichQueryFields(
|
|
184
133
|
query.fields,
|
|
185
134
|
ctx.request.body.parameters
|
|
186
135
|
)
|
|
187
|
-
const integration = new Integration(datasource.config)
|
|
188
136
|
|
|
189
137
|
// call the relevant CRUD method on the integration class
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
138
|
+
try {
|
|
139
|
+
const { rows } = await Runner.run({
|
|
140
|
+
datasource,
|
|
141
|
+
queryVerb: query.queryVerb,
|
|
142
|
+
query: enrichedQuery,
|
|
143
|
+
transformer: query.transformer,
|
|
144
|
+
})
|
|
145
|
+
ctx.body = rows
|
|
146
|
+
} catch (err) {
|
|
147
|
+
ctx.throw(400, err)
|
|
200
148
|
}
|
|
201
149
|
}
|
|
202
150
|
|
|
@@ -33,10 +33,11 @@ interface RunConfig {
|
|
|
33
33
|
sort?: SortJson
|
|
34
34
|
paginate?: PaginationJson
|
|
35
35
|
row?: Row
|
|
36
|
+
rows?: Row[]
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
module External {
|
|
39
|
-
const {
|
|
40
|
+
const { getDatasourceAndQuery } = require("./utils")
|
|
40
41
|
const {
|
|
41
42
|
DataSourceOperation,
|
|
42
43
|
FieldTypes,
|
|
@@ -46,6 +47,7 @@ module External {
|
|
|
46
47
|
const { processObjectSync } = require("@budibase/string-templates")
|
|
47
48
|
const { cloneDeep } = require("lodash/fp")
|
|
48
49
|
const CouchDB = require("../../../db")
|
|
50
|
+
const { processFormulas } = require("../../../utilities/rowProcessor/utils")
|
|
49
51
|
|
|
50
52
|
function buildFilters(
|
|
51
53
|
id: string | undefined,
|
|
@@ -162,8 +164,8 @@ module External {
|
|
|
162
164
|
}
|
|
163
165
|
}
|
|
164
166
|
|
|
165
|
-
function basicProcessing(row: Row, table: Table) {
|
|
166
|
-
const thisRow:
|
|
167
|
+
function basicProcessing(row: Row, table: Table): Row {
|
|
168
|
+
const thisRow: Row = {}
|
|
167
169
|
// filter the row down to what is actually the row (not joined)
|
|
168
170
|
for (let fieldName of Object.keys(table.schema)) {
|
|
169
171
|
const value = row[`${table.name}.${fieldName}`] || row[fieldName]
|
|
@@ -178,6 +180,23 @@ module External {
|
|
|
178
180
|
return thisRow
|
|
179
181
|
}
|
|
180
182
|
|
|
183
|
+
function fixArrayTypes(row: Row, table: Table) {
|
|
184
|
+
for (let [fieldName, schema] of Object.entries(table.schema)) {
|
|
185
|
+
if (
|
|
186
|
+
schema.type === FieldTypes.ARRAY &&
|
|
187
|
+
typeof row[fieldName] === "string"
|
|
188
|
+
) {
|
|
189
|
+
try {
|
|
190
|
+
row[fieldName] = JSON.parse(row[fieldName])
|
|
191
|
+
} catch (err) {
|
|
192
|
+
// couldn't convert back to array, ignore
|
|
193
|
+
delete row[fieldName]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return row
|
|
198
|
+
}
|
|
199
|
+
|
|
181
200
|
function isMany(field: FieldSchema) {
|
|
182
201
|
return (
|
|
183
202
|
field.relationshipType && field.relationshipType.split("-")[0] === "many"
|
|
@@ -225,7 +244,12 @@ module External {
|
|
|
225
244
|
manyRelationships: ManyRelationship[] = []
|
|
226
245
|
for (let [key, field] of Object.entries(table.schema)) {
|
|
227
246
|
// if set already, or not set just skip it
|
|
228
|
-
if (
|
|
247
|
+
if (
|
|
248
|
+
row[key] == null ||
|
|
249
|
+
newRow[key] ||
|
|
250
|
+
field.autocolumn ||
|
|
251
|
+
field.type === FieldTypes.FORMULA
|
|
252
|
+
) {
|
|
229
253
|
continue
|
|
230
254
|
}
|
|
231
255
|
// if its an empty string then it means return the column to null (if possible)
|
|
@@ -336,7 +360,7 @@ module External {
|
|
|
336
360
|
table: Table,
|
|
337
361
|
relationships: RelationshipsJson[]
|
|
338
362
|
) {
|
|
339
|
-
if (rows[0].read === true) {
|
|
363
|
+
if (!rows || rows.length === 0 || rows[0].read === true) {
|
|
340
364
|
return []
|
|
341
365
|
}
|
|
342
366
|
let finalRows: { [key: string]: Row } = {}
|
|
@@ -352,7 +376,10 @@ module External {
|
|
|
352
376
|
)
|
|
353
377
|
continue
|
|
354
378
|
}
|
|
355
|
-
const thisRow = basicProcessing(row, table)
|
|
379
|
+
const thisRow = fixArrayTypes(basicProcessing(row, table), table)
|
|
380
|
+
if (thisRow._id == null) {
|
|
381
|
+
throw "Unable to generate row ID for SQL rows"
|
|
382
|
+
}
|
|
356
383
|
finalRows[thisRow._id] = thisRow
|
|
357
384
|
// do this at end once its been added to the final rows
|
|
358
385
|
finalRows = this.updateRelationshipColumns(
|
|
@@ -361,7 +388,7 @@ module External {
|
|
|
361
388
|
relationships
|
|
362
389
|
)
|
|
363
390
|
}
|
|
364
|
-
return Object.values(finalRows)
|
|
391
|
+
return processFormulas(table, Object.values(finalRows))
|
|
365
392
|
}
|
|
366
393
|
|
|
367
394
|
/**
|
|
@@ -428,7 +455,7 @@ module External {
|
|
|
428
455
|
const tableId = isMany ? field.through : field.tableId
|
|
429
456
|
const manyKey = field.throughFrom || primaryKey
|
|
430
457
|
const fieldName = isMany ? manyKey : field.fieldName
|
|
431
|
-
const response = await
|
|
458
|
+
const response = await getDatasourceAndQuery(this.appId, {
|
|
432
459
|
endpoint: getEndpoint(tableId, DataSourceOperation.READ),
|
|
433
460
|
filters: {
|
|
434
461
|
equal: {
|
|
@@ -479,7 +506,7 @@ module External {
|
|
|
479
506
|
: DataSourceOperation.CREATE
|
|
480
507
|
if (!found) {
|
|
481
508
|
promises.push(
|
|
482
|
-
|
|
509
|
+
getDatasourceAndQuery(appId, {
|
|
483
510
|
endpoint: getEndpoint(tableId, operation),
|
|
484
511
|
// if we're doing many relationships then we're writing, only one response
|
|
485
512
|
body,
|
|
@@ -509,7 +536,7 @@ module External {
|
|
|
509
536
|
: DataSourceOperation.UPDATE
|
|
510
537
|
const body = isMany ? null : { [colName]: null }
|
|
511
538
|
promises.push(
|
|
512
|
-
|
|
539
|
+
getDatasourceAndQuery(this.appId, {
|
|
513
540
|
endpoint: getEndpoint(tableId, op),
|
|
514
541
|
body,
|
|
515
542
|
filters,
|
|
@@ -532,16 +559,17 @@ module External {
|
|
|
532
559
|
table: Table,
|
|
533
560
|
includeRelations: IncludeRelationships = IncludeRelationships.INCLUDE
|
|
534
561
|
) {
|
|
535
|
-
function
|
|
562
|
+
function extractRealFields(table: Table, existing: string[] = []) {
|
|
536
563
|
return Object.entries(table.schema)
|
|
537
564
|
.filter(
|
|
538
565
|
column =>
|
|
539
566
|
column[1].type !== FieldTypes.LINK &&
|
|
567
|
+
column[1].type !== FieldTypes.FORMULA &&
|
|
540
568
|
!existing.find((field: string) => field === column[0])
|
|
541
569
|
)
|
|
542
570
|
.map(column => `${table.name}.${column[0]}`)
|
|
543
571
|
}
|
|
544
|
-
let fields =
|
|
572
|
+
let fields = extractRealFields(table)
|
|
545
573
|
for (let field of Object.values(table.schema)) {
|
|
546
574
|
if (field.type !== FieldTypes.LINK || !includeRelations) {
|
|
547
575
|
continue
|
|
@@ -549,7 +577,7 @@ module External {
|
|
|
549
577
|
const { tableName: linkTableName } = breakExternalTableId(field.tableId)
|
|
550
578
|
const linkTable = this.tables[linkTableName]
|
|
551
579
|
if (linkTable) {
|
|
552
|
-
const linkedFields =
|
|
580
|
+
const linkedFields = extractRealFields(linkTable, fields)
|
|
553
581
|
fields = fields.concat(linkedFields)
|
|
554
582
|
}
|
|
555
583
|
}
|
|
@@ -573,7 +601,10 @@ module External {
|
|
|
573
601
|
throw `Unable to process query, table "${tableName}" not defined.`
|
|
574
602
|
}
|
|
575
603
|
// look for specific components of config which may not be considered acceptable
|
|
576
|
-
let { id, row, filters, sort, paginate } = cleanupConfig(
|
|
604
|
+
let { id, row, filters, sort, paginate, rows } = cleanupConfig(
|
|
605
|
+
config,
|
|
606
|
+
table
|
|
607
|
+
)
|
|
577
608
|
filters = buildFilters(id, filters || {}, table)
|
|
578
609
|
const relationships = this.buildRelationships(table)
|
|
579
610
|
// clean up row on ingress using schema
|
|
@@ -599,7 +630,7 @@ module External {
|
|
|
599
630
|
sort,
|
|
600
631
|
paginate,
|
|
601
632
|
relationships,
|
|
602
|
-
body: row,
|
|
633
|
+
body: row || rows,
|
|
603
634
|
// pass an id filter into extra, purely for mysql/returning
|
|
604
635
|
extra: {
|
|
605
636
|
idFilter: buildFilters(id || generateIdForRow(row, table), {}, table),
|
|
@@ -609,7 +640,7 @@ module External {
|
|
|
609
640
|
},
|
|
610
641
|
}
|
|
611
642
|
// can't really use response right now
|
|
612
|
-
const response = await
|
|
643
|
+
const response = await getDatasourceAndQuery(appId, json)
|
|
613
644
|
// handle many to many relationships now if we know the ID (could be auto increment)
|
|
614
645
|
if (
|
|
615
646
|
operation !== DataSourceOperation.READ &&
|
|
@@ -30,6 +30,8 @@ async function handleRequest(appId, operation, tableId, opts = {}) {
|
|
|
30
30
|
)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
exports.handleRequest = handleRequest
|
|
34
|
+
|
|
33
35
|
exports.patch = async ctx => {
|
|
34
36
|
const appId = ctx.appId
|
|
35
37
|
const inputs = ctx.request.body
|
|
@@ -55,7 +57,8 @@ exports.save = async ctx => {
|
|
|
55
57
|
exports.fetchView = async ctx => {
|
|
56
58
|
// there are no views in external data sources, shouldn't ever be called
|
|
57
59
|
// for now just fetch
|
|
58
|
-
|
|
60
|
+
const split = ctx.params.viewName.split("all_")
|
|
61
|
+
ctx.params.tableId = split[1] ? split[1] : split[0]
|
|
59
62
|
return exports.fetch(ctx)
|
|
60
63
|
}
|
|
61
64
|
|
|
@@ -4,8 +4,8 @@ const CouchDB = require("../../../db")
|
|
|
4
4
|
const { InternalTables } = require("../../../db/utils")
|
|
5
5
|
const userController = require("../user")
|
|
6
6
|
const { FieldTypes } = require("../../../constants")
|
|
7
|
-
const { integrations } = require("../../../integrations")
|
|
8
7
|
const { processStringSync } = require("@budibase/string-templates")
|
|
8
|
+
const { makeExternalQuery } = require("../../../integrations/base/utils")
|
|
9
9
|
|
|
10
10
|
validateJs.extend(validateJs.validators.datetime, {
|
|
11
11
|
parse: function (value) {
|
|
@@ -17,18 +17,11 @@ validateJs.extend(validateJs.validators.datetime, {
|
|
|
17
17
|
},
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
exports.
|
|
20
|
+
exports.getDatasourceAndQuery = async (appId, json) => {
|
|
21
21
|
const datasourceId = json.endpoint.datasourceId
|
|
22
22
|
const db = new CouchDB(appId)
|
|
23
23
|
const datasource = await db.get(datasourceId)
|
|
24
|
-
|
|
25
|
-
// query is the opinionated function
|
|
26
|
-
if (Integration.prototype.query) {
|
|
27
|
-
const integration = new Integration(datasource.config)
|
|
28
|
-
return integration.query(json)
|
|
29
|
-
} else {
|
|
30
|
-
throw "Datasource does not support query."
|
|
31
|
-
}
|
|
24
|
+
return makeExternalQuery(datasource, json)
|
|
32
25
|
}
|
|
33
26
|
|
|
34
27
|
exports.findRow = async (ctx, db, tableId, rowId) => {
|
|
@@ -68,7 +61,11 @@ exports.validate = async ({ appId, tableId, row, table }) => {
|
|
|
68
61
|
let res
|
|
69
62
|
|
|
70
63
|
// Validate.js doesn't seem to handle array
|
|
71
|
-
if (
|
|
64
|
+
if (
|
|
65
|
+
table.schema[fieldName].type === FieldTypes.ARRAY &&
|
|
66
|
+
row[fieldName] &&
|
|
67
|
+
row[fieldName].length
|
|
68
|
+
) {
|
|
72
69
|
row[fieldName].map(val => {
|
|
73
70
|
if (!constraints.inclusion.includes(val)) {
|
|
74
71
|
errors[fieldName] = "Field not in list"
|