@budibase/server 0.9.188 → 0.9.190-alpha.10
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/__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.2bd3b345.js +1316 -0
- package/builder/assets/index.4fb3f887.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 +1608 -1191
- package/coverage/coverage-final.json +97 -93
- 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 +113 -80
- 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 +245 -41
- 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 +98 -98
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +9 -9
- 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 +79 -229
- package/coverage/lcov-report/api/controllers/role.js.html +9 -9
- package/coverage/lcov-report/api/controllers/routing.js.html +29 -29
- 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 +3 -3
- 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 +533 -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 +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/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 +536 -2
- 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 +464 -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 +46 -16
- 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 +2 -2
- 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 +4 -4
- package/coverage/lcov-report/db/utils.js.html +75 -75
- 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 +106 -91
- 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 +19 -16
- package/coverage/lcov-report/middleware/builder.js.html +22 -13
- package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
- package/coverage/lcov-report/middleware/index.html +23 -23
- 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 +2 -2
- 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 +38 -23
- package/coverage/lcov-report/utilities/index.html +48 -48
- package/coverage/lcov-report/utilities/index.js.html +49 -16
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +31 -10
- 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 +2 -2
- 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 +2687 -1942
- package/dist/api/controllers/application.js +16 -6
- 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 +32 -62
- package/dist/api/controllers/row/ExternalRequest.js +83 -36
- 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 +146 -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/row.js +178 -0
- package/dist/api/routes/table.js +150 -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 +17 -1
- 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 +350 -177
- 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 +16 -85
- package/dist/integrations/oracle.js +367 -0
- package/dist/integrations/postgres.js +35 -28
- package/dist/integrations/utils.js +71 -9
- package/dist/middleware/authorized.js +2 -1
- package/dist/middleware/builder.js +4 -1
- package/dist/package.json +18 -9
- 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 +19 -10
- package/scripts/dev/manage.js +1 -0
- package/scripts/docs/README.md +31 -0
- package/scripts/docs/generate.js +74 -0
- package/scripts/docs/toSwagger.js +320 -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 -7
- 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 +35 -85
- package/src/api/controllers/row/ExternalRequest.ts +99 -38
- 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 +151 -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/row.js +178 -0
- package/src/api/routes/table.js +154 -0
- package/src/api/routes/tests/application.spec.js +0 -2
- 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 +38 -9
- package/src/api/routes/tests/screen.spec.js +1 -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 +21 -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 +375 -218
- 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 +23 -95
- package/src/integrations/oracle.ts +464 -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 +78 -8
- package/src/middleware/authorized.js +2 -1
- package/src/middleware/builder.js +4 -1
- 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.550fdba7.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
|
@@ -24,12 +24,13 @@ const datasource_1 = require("../../../definitions/datasource");
|
|
|
24
24
|
const utils_1 = require("../../../integrations/utils");
|
|
25
25
|
var External;
|
|
26
26
|
(function (External) {
|
|
27
|
-
const {
|
|
27
|
+
const { getDatasourceAndQuery } = require("./utils");
|
|
28
28
|
const { DataSourceOperation, FieldTypes, RelationshipTypes, } = require("../../../constants");
|
|
29
29
|
const { breakExternalTableId, isSQL } = require("../../../integrations/utils");
|
|
30
30
|
const { processObjectSync } = require("@budibase/string-templates");
|
|
31
31
|
const { cloneDeep } = require("lodash/fp");
|
|
32
32
|
const CouchDB = require("../../../db");
|
|
33
|
+
const { processFormulas } = require("../../../utilities/rowProcessor/utils");
|
|
33
34
|
function buildFilters(id, filters, table) {
|
|
34
35
|
const primary = table.primary;
|
|
35
36
|
// if passed in array need to copy for shifting etc
|
|
@@ -94,8 +95,11 @@ var External;
|
|
|
94
95
|
};
|
|
95
96
|
// check the row and filters to make sure they aren't a key of some sort
|
|
96
97
|
if (config.filters) {
|
|
97
|
-
for (let filter of Object.
|
|
98
|
-
|
|
98
|
+
for (let [key, filter] of Object.entries(config.filters)) {
|
|
99
|
+
// oneOf is an array, don't iterate it
|
|
100
|
+
if (typeof filter !== "object" ||
|
|
101
|
+
Object.keys(filter).length === 0 ||
|
|
102
|
+
key === datasource_1.FilterTypes.ONE_OF) {
|
|
99
103
|
continue;
|
|
100
104
|
}
|
|
101
105
|
iterateObject(filter);
|
|
@@ -151,8 +155,23 @@ var External;
|
|
|
151
155
|
thisRow._rev = "rev";
|
|
152
156
|
return thisRow;
|
|
153
157
|
}
|
|
154
|
-
function
|
|
155
|
-
|
|
158
|
+
function fixArrayTypes(row, table) {
|
|
159
|
+
for (let [fieldName, schema] of Object.entries(table.schema)) {
|
|
160
|
+
if (schema.type === FieldTypes.ARRAY &&
|
|
161
|
+
typeof row[fieldName] === "string") {
|
|
162
|
+
try {
|
|
163
|
+
row[fieldName] = JSON.parse(row[fieldName]);
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
// couldn't convert back to array, ignore
|
|
167
|
+
delete row[fieldName];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return row;
|
|
172
|
+
}
|
|
173
|
+
function isOneSide(field) {
|
|
174
|
+
return (field.relationshipType && field.relationshipType.split("-")[0] === "one");
|
|
156
175
|
}
|
|
157
176
|
class ExternalRequest {
|
|
158
177
|
constructor(appId, operation, tableId, datasource) {
|
|
@@ -182,7 +201,10 @@ var External;
|
|
|
182
201
|
let newRow = {}, manyRelationships = [];
|
|
183
202
|
for (let [key, field] of Object.entries(table.schema)) {
|
|
184
203
|
// if set already, or not set just skip it
|
|
185
|
-
if (
|
|
204
|
+
if (row[key] == null ||
|
|
205
|
+
newRow[key] ||
|
|
206
|
+
field.autocolumn ||
|
|
207
|
+
field.type === FieldTypes.FORMULA) {
|
|
186
208
|
continue;
|
|
187
209
|
}
|
|
188
210
|
// if its an empty string then it means return the column to null (if possible)
|
|
@@ -207,24 +229,35 @@ var External;
|
|
|
207
229
|
const linkTable = this.tables[linkTableName];
|
|
208
230
|
// @ts-ignore
|
|
209
231
|
const linkTablePrimary = linkTable.primary[0];
|
|
210
|
-
|
|
232
|
+
// one to many
|
|
233
|
+
if (isOneSide(field)) {
|
|
211
234
|
newRow[field.foreignKey || linkTablePrimary] = utils_1.breakRowIdField(row[key][0])[0];
|
|
212
235
|
}
|
|
213
|
-
|
|
236
|
+
// many to many
|
|
237
|
+
else if (field.through) {
|
|
214
238
|
// we're not inserting a doc, will be a bunch of update calls
|
|
215
|
-
const
|
|
216
|
-
const thisKey =
|
|
217
|
-
? "id"
|
|
218
|
-
: field.throughTo || linkTablePrimary;
|
|
219
|
-
// @ts-ignore
|
|
220
|
-
const otherKey = isUpdate
|
|
221
|
-
? field.fieldName
|
|
222
|
-
: field.throughFrom || tablePrimary;
|
|
239
|
+
const otherKey = field.throughFrom || linkTablePrimary;
|
|
240
|
+
const thisKey = field.throughTo || tablePrimary;
|
|
223
241
|
row[key].map((relationship) => {
|
|
224
|
-
// we don't really support composite keys for relationships, this is why [0] is used
|
|
225
242
|
manyRelationships.push({
|
|
226
243
|
tableId: field.through || field.tableId,
|
|
227
|
-
isUpdate,
|
|
244
|
+
isUpdate: false,
|
|
245
|
+
key: otherKey,
|
|
246
|
+
[otherKey]: utils_1.breakRowIdField(relationship)[0],
|
|
247
|
+
// leave the ID for enrichment later
|
|
248
|
+
[thisKey]: `{{ literal ${tablePrimary} }}`,
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
// many to one
|
|
253
|
+
else {
|
|
254
|
+
const thisKey = "id";
|
|
255
|
+
// @ts-ignore
|
|
256
|
+
const otherKey = field.fieldName;
|
|
257
|
+
row[key].map((relationship) => {
|
|
258
|
+
manyRelationships.push({
|
|
259
|
+
tableId: field.tableId,
|
|
260
|
+
isUpdate: true,
|
|
228
261
|
key: otherKey,
|
|
229
262
|
[thisKey]: utils_1.breakRowIdField(relationship)[0],
|
|
230
263
|
// leave the ID for enrichment later
|
|
@@ -278,7 +311,7 @@ var External;
|
|
|
278
311
|
return rows;
|
|
279
312
|
}
|
|
280
313
|
outputProcessing(rows = [], table, relationships) {
|
|
281
|
-
if (rows[0].read === true) {
|
|
314
|
+
if (!rows || rows.length === 0 || rows[0].read === true) {
|
|
282
315
|
return [];
|
|
283
316
|
}
|
|
284
317
|
let finalRows = {};
|
|
@@ -290,12 +323,15 @@ var External;
|
|
|
290
323
|
finalRows = this.updateRelationshipColumns(row, finalRows, relationships);
|
|
291
324
|
continue;
|
|
292
325
|
}
|
|
293
|
-
const thisRow = basicProcessing(row, table);
|
|
326
|
+
const thisRow = fixArrayTypes(basicProcessing(row, table), table);
|
|
327
|
+
if (thisRow._id == null) {
|
|
328
|
+
throw "Unable to generate row ID for SQL rows";
|
|
329
|
+
}
|
|
294
330
|
finalRows[thisRow._id] = thisRow;
|
|
295
331
|
// do this at end once its been added to the final rows
|
|
296
332
|
finalRows = this.updateRelationshipColumns(row, finalRows, relationships);
|
|
297
333
|
}
|
|
298
|
-
return Object.values(finalRows);
|
|
334
|
+
return processFormulas(table, Object.values(finalRows));
|
|
299
335
|
}
|
|
300
336
|
/**
|
|
301
337
|
* Gets the list of relationship JSON structures based on the columns in the table,
|
|
@@ -329,8 +365,8 @@ var External;
|
|
|
329
365
|
const { tableName: throughTableName } = breakExternalTableId(field.through);
|
|
330
366
|
definition.through = throughTableName;
|
|
331
367
|
// don't support composite keys for relationships
|
|
332
|
-
definition.from = field.
|
|
333
|
-
definition.to = field.
|
|
368
|
+
definition.from = field.throughTo || table.primary[0];
|
|
369
|
+
definition.to = field.throughFrom || linkTable.primary[0];
|
|
334
370
|
definition.fromPrimary = table.primary[0];
|
|
335
371
|
definition.toPrimary = linkTable.primary[0];
|
|
336
372
|
}
|
|
@@ -352,24 +388,34 @@ var External;
|
|
|
352
388
|
// make a new request to get the row with all its relationships
|
|
353
389
|
// we need this to work out if any relationships need removed
|
|
354
390
|
for (let field of Object.values(table.schema)) {
|
|
355
|
-
if (field.type !== FieldTypes.LINK ||
|
|
391
|
+
if (field.type !== FieldTypes.LINK ||
|
|
392
|
+
!field.fieldName ||
|
|
393
|
+
isOneSide(field)) {
|
|
356
394
|
continue;
|
|
357
395
|
}
|
|
358
396
|
const isMany = field.relationshipType === RelationshipTypes.MANY_TO_MANY;
|
|
359
397
|
const tableId = isMany ? field.through : field.tableId;
|
|
360
|
-
const
|
|
398
|
+
const { tableName: relatedTableName } = breakExternalTableId(tableId);
|
|
399
|
+
// @ts-ignore
|
|
400
|
+
const linkPrimaryKey = this.tables[relatedTableName].primary[0];
|
|
401
|
+
const manyKey = field.throughTo || primaryKey;
|
|
402
|
+
const lookupField = isMany ? primaryKey : field.foreignKey;
|
|
361
403
|
const fieldName = isMany ? manyKey : field.fieldName;
|
|
362
|
-
|
|
404
|
+
if (!lookupField || !row[lookupField]) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
const response = yield getDatasourceAndQuery(this.appId, {
|
|
363
408
|
endpoint: getEndpoint(tableId, DataSourceOperation.READ),
|
|
364
409
|
filters: {
|
|
365
410
|
equal: {
|
|
366
|
-
[fieldName]: row[
|
|
411
|
+
[fieldName]: row[lookupField],
|
|
367
412
|
},
|
|
368
413
|
},
|
|
369
414
|
});
|
|
370
415
|
// this is the response from knex if no rows found
|
|
371
416
|
const rows = !response[0].read ? response : [];
|
|
372
|
-
|
|
417
|
+
const storeTo = isMany ? field.throughFrom || linkPrimaryKey : manyKey;
|
|
418
|
+
related[storeTo] = { rows, isMany, tableId };
|
|
373
419
|
}
|
|
374
420
|
return related;
|
|
375
421
|
});
|
|
@@ -403,7 +449,7 @@ var External;
|
|
|
403
449
|
? DataSourceOperation.UPDATE
|
|
404
450
|
: DataSourceOperation.CREATE;
|
|
405
451
|
if (!found) {
|
|
406
|
-
promises.push(
|
|
452
|
+
promises.push(getDatasourceAndQuery(appId, {
|
|
407
453
|
endpoint: getEndpoint(tableId, operation),
|
|
408
454
|
// if we're doing many relationships then we're writing, only one response
|
|
409
455
|
body,
|
|
@@ -430,7 +476,7 @@ var External;
|
|
|
430
476
|
? DataSourceOperation.DELETE
|
|
431
477
|
: DataSourceOperation.UPDATE;
|
|
432
478
|
const body = isMany ? null : { [colName]: null };
|
|
433
|
-
promises.push(
|
|
479
|
+
promises.push(getDatasourceAndQuery(this.appId, {
|
|
434
480
|
endpoint: getEndpoint(tableId, op),
|
|
435
481
|
body,
|
|
436
482
|
filters,
|
|
@@ -449,13 +495,14 @@ var External;
|
|
|
449
495
|
* is more performant and has the added benefit of protecting against this scenario.
|
|
450
496
|
*/
|
|
451
497
|
buildFields(table, includeRelations = datasource_1.IncludeRelationships.INCLUDE) {
|
|
452
|
-
function
|
|
498
|
+
function extractRealFields(table, existing = []) {
|
|
453
499
|
return Object.entries(table.schema)
|
|
454
500
|
.filter(column => column[1].type !== FieldTypes.LINK &&
|
|
501
|
+
column[1].type !== FieldTypes.FORMULA &&
|
|
455
502
|
!existing.find((field) => field === column[0]))
|
|
456
503
|
.map(column => `${table.name}.${column[0]}`);
|
|
457
504
|
}
|
|
458
|
-
let fields =
|
|
505
|
+
let fields = extractRealFields(table);
|
|
459
506
|
for (let field of Object.values(table.schema)) {
|
|
460
507
|
if (field.type !== FieldTypes.LINK || !includeRelations) {
|
|
461
508
|
continue;
|
|
@@ -463,7 +510,7 @@ var External;
|
|
|
463
510
|
const { tableName: linkTableName } = breakExternalTableId(field.tableId);
|
|
464
511
|
const linkTable = this.tables[linkTableName];
|
|
465
512
|
if (linkTable) {
|
|
466
|
-
const linkedFields =
|
|
513
|
+
const linkedFields = extractRealFields(linkTable, fields);
|
|
467
514
|
fields = fields.concat(linkedFields);
|
|
468
515
|
}
|
|
469
516
|
}
|
|
@@ -487,7 +534,7 @@ var External;
|
|
|
487
534
|
throw `Unable to process query, table "${tableName}" not defined.`;
|
|
488
535
|
}
|
|
489
536
|
// look for specific components of config which may not be considered acceptable
|
|
490
|
-
let { id, row, filters, sort, paginate } = cleanupConfig(config, table);
|
|
537
|
+
let { id, row, filters, sort, paginate, rows } = cleanupConfig(config, table);
|
|
491
538
|
filters = buildFilters(id, filters || {}, table);
|
|
492
539
|
const relationships = this.buildRelationships(table);
|
|
493
540
|
// clean up row on ingress using schema
|
|
@@ -511,7 +558,7 @@ var External;
|
|
|
511
558
|
sort,
|
|
512
559
|
paginate,
|
|
513
560
|
relationships,
|
|
514
|
-
body: row,
|
|
561
|
+
body: row || rows,
|
|
515
562
|
// pass an id filter into extra, purely for mysql/returning
|
|
516
563
|
extra: {
|
|
517
564
|
idFilter: buildFilters(id || generateIdForRow(row, table), {}, table),
|
|
@@ -521,7 +568,7 @@ var External;
|
|
|
521
568
|
},
|
|
522
569
|
};
|
|
523
570
|
// can't really use response right now
|
|
524
|
-
const response = yield
|
|
571
|
+
const response = yield getDatasourceAndQuery(appId, json);
|
|
525
572
|
// handle many to many relationships now if we know the ID (could be auto increment)
|
|
526
573
|
if (operation !== DataSourceOperation.READ &&
|
|
527
574
|
processed.manyRelationships) {
|
|
@@ -41,6 +41,7 @@ function handleRequest(appId, operation, tableId, opts = {}) {
|
|
|
41
41
|
return new ExternalRequest(appId, operation, tableId, opts.datasource).run(opts);
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
+
exports.handleRequest = handleRequest;
|
|
44
45
|
exports.patch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
46
|
const appId = ctx.appId;
|
|
46
47
|
const inputs = ctx.request.body;
|
|
@@ -64,7 +65,8 @@ exports.save = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
64
65
|
exports.fetchView = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65
66
|
// there are no views in external data sources, shouldn't ever be called
|
|
66
67
|
// for now just fetch
|
|
67
|
-
|
|
68
|
+
const split = ctx.params.viewName.split("all_");
|
|
69
|
+
ctx.params.tableId = split[1] ? split[1] : split[0];
|
|
68
70
|
return exports.fetch(ctx);
|
|
69
71
|
});
|
|
70
72
|
exports.fetch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -14,8 +14,8 @@ const CouchDB = require("../../../db");
|
|
|
14
14
|
const { InternalTables } = require("../../../db/utils");
|
|
15
15
|
const userController = require("../user");
|
|
16
16
|
const { FieldTypes } = require("../../../constants");
|
|
17
|
-
const { integrations } = require("../../../integrations");
|
|
18
17
|
const { processStringSync } = require("@budibase/string-templates");
|
|
18
|
+
const { makeExternalQuery } = require("../../../integrations/base/utils");
|
|
19
19
|
validateJs.extend(validateJs.validators.datetime, {
|
|
20
20
|
parse: function (value) {
|
|
21
21
|
return new Date(value).getTime();
|
|
@@ -25,19 +25,11 @@ validateJs.extend(validateJs.validators.datetime, {
|
|
|
25
25
|
return new Date(value).toISOString();
|
|
26
26
|
},
|
|
27
27
|
});
|
|
28
|
-
exports.
|
|
28
|
+
exports.getDatasourceAndQuery = (appId, json) => __awaiter(void 0, void 0, void 0, function* () {
|
|
29
29
|
const datasourceId = json.endpoint.datasourceId;
|
|
30
30
|
const db = new CouchDB(appId);
|
|
31
31
|
const datasource = yield db.get(datasourceId);
|
|
32
|
-
|
|
33
|
-
// query is the opinionated function
|
|
34
|
-
if (Integration.prototype.query) {
|
|
35
|
-
const integration = new Integration(datasource.config);
|
|
36
|
-
return integration.query(json);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
throw "Datasource does not support query.";
|
|
40
|
-
}
|
|
32
|
+
return makeExternalQuery(datasource, json);
|
|
41
33
|
});
|
|
42
34
|
exports.findRow = (ctx, db, tableId, rowId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
43
35
|
let row;
|
|
@@ -73,7 +65,9 @@ exports.validate = ({ appId, tableId, row, table }) => __awaiter(void 0, void 0,
|
|
|
73
65
|
}
|
|
74
66
|
let res;
|
|
75
67
|
// Validate.js doesn't seem to handle array
|
|
76
|
-
if (table.schema[fieldName].type === FieldTypes.ARRAY
|
|
68
|
+
if (table.schema[fieldName].type === FieldTypes.ARRAY &&
|
|
69
|
+
row[fieldName] &&
|
|
70
|
+
row[fieldName].length) {
|
|
77
71
|
row[fieldName].map(val => {
|
|
78
72
|
if (!constraints.inclusion.includes(val)) {
|
|
79
73
|
errors[fieldName] = "Field not in list";
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
const CouchDB = require("../../../db");
|
|
12
|
+
const { buildExternalTableId, breakExternalTableId, } = require("../../../integrations/utils");
|
|
13
|
+
const { getTable, generateForeignKey, generateJunctionTableName, foreignKeyStructure, hasTypeChanged, } = require("./utils");
|
|
14
|
+
const { DataSourceOperation, FieldTypes, RelationshipTypes, } = require("../../../constants");
|
|
15
|
+
const { makeExternalQuery } = require("../../../integrations/base/utils");
|
|
16
|
+
const { cloneDeep } = require("lodash/fp");
|
|
17
|
+
const csvParser = require("../../../utilities/csvParser");
|
|
18
|
+
const { handleRequest } = require("../row/external");
|
|
19
|
+
function makeTableRequest(datasource, operation, table, tables, oldTable = null) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const json = {
|
|
22
|
+
endpoint: {
|
|
23
|
+
datasourceId: datasource._id,
|
|
24
|
+
entityId: table._id,
|
|
25
|
+
operation,
|
|
26
|
+
},
|
|
27
|
+
meta: {
|
|
28
|
+
tables,
|
|
29
|
+
},
|
|
30
|
+
table,
|
|
31
|
+
};
|
|
32
|
+
if (oldTable) {
|
|
33
|
+
json.meta.table = oldTable;
|
|
34
|
+
}
|
|
35
|
+
return makeExternalQuery(datasource, json);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function cleanupRelationships(table, tables, oldTable = null) {
|
|
39
|
+
const tableToIterate = oldTable ? oldTable : table;
|
|
40
|
+
// clean up relationships in couch table schemas
|
|
41
|
+
for (let [key, schema] of Object.entries(tableToIterate.schema)) {
|
|
42
|
+
if (schema.type === FieldTypes.LINK &&
|
|
43
|
+
(!oldTable || table.schema[key] == null)) {
|
|
44
|
+
const relatedTable = Object.values(tables).find(table => table._id === schema.tableId);
|
|
45
|
+
const foreignKey = schema.foreignKey;
|
|
46
|
+
if (!relatedTable || !foreignKey) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
for (let [relatedKey, relatedSchema] of Object.entries(relatedTable.schema)) {
|
|
50
|
+
if (relatedSchema.type === FieldTypes.LINK &&
|
|
51
|
+
relatedSchema.fieldName === foreignKey) {
|
|
52
|
+
delete relatedTable.schema[relatedKey];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function getDatasourceId(table) {
|
|
59
|
+
if (!table) {
|
|
60
|
+
throw "No table supplied";
|
|
61
|
+
}
|
|
62
|
+
if (table.sourceId) {
|
|
63
|
+
return table.sourceId;
|
|
64
|
+
}
|
|
65
|
+
return breakExternalTableId(table._id).datasourceId;
|
|
66
|
+
}
|
|
67
|
+
function otherRelationshipType(type) {
|
|
68
|
+
if (type === RelationshipTypes.MANY_TO_MANY) {
|
|
69
|
+
return RelationshipTypes.MANY_TO_MANY;
|
|
70
|
+
}
|
|
71
|
+
return type === RelationshipTypes.ONE_TO_MANY
|
|
72
|
+
? RelationshipTypes.MANY_TO_ONE
|
|
73
|
+
: RelationshipTypes.ONE_TO_MANY;
|
|
74
|
+
}
|
|
75
|
+
function generateManyLinkSchema(datasource, column, table, relatedTable) {
|
|
76
|
+
const primary = table.name + table.primary[0];
|
|
77
|
+
const relatedPrimary = relatedTable.name + relatedTable.primary[0];
|
|
78
|
+
const jcTblName = generateJunctionTableName(column, table, relatedTable);
|
|
79
|
+
// first create the new table
|
|
80
|
+
const junctionTable = {
|
|
81
|
+
_id: buildExternalTableId(datasource._id, jcTblName),
|
|
82
|
+
name: jcTblName,
|
|
83
|
+
primary: [primary, relatedPrimary],
|
|
84
|
+
constrained: [primary, relatedPrimary],
|
|
85
|
+
schema: {
|
|
86
|
+
[primary]: foreignKeyStructure(primary, {
|
|
87
|
+
toTable: table.name,
|
|
88
|
+
toKey: table.primary[0],
|
|
89
|
+
}),
|
|
90
|
+
[relatedPrimary]: foreignKeyStructure(relatedPrimary, {
|
|
91
|
+
toTable: relatedTable.name,
|
|
92
|
+
toKey: relatedTable.primary[0],
|
|
93
|
+
}),
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
column.through = junctionTable._id;
|
|
97
|
+
column.throughFrom = primary;
|
|
98
|
+
column.throughTo = relatedPrimary;
|
|
99
|
+
column.fieldName = relatedPrimary;
|
|
100
|
+
return junctionTable;
|
|
101
|
+
}
|
|
102
|
+
function generateLinkSchema(column, table, relatedTable, type) {
|
|
103
|
+
const isOneSide = type === RelationshipTypes.ONE_TO_MANY;
|
|
104
|
+
const primary = isOneSide ? relatedTable.primary[0] : table.primary[0];
|
|
105
|
+
// generate a foreign key
|
|
106
|
+
const foreignKey = generateForeignKey(column, relatedTable);
|
|
107
|
+
column.relationshipType = type;
|
|
108
|
+
column.foreignKey = isOneSide ? foreignKey : primary;
|
|
109
|
+
column.fieldName = isOneSide ? primary : foreignKey;
|
|
110
|
+
return foreignKey;
|
|
111
|
+
}
|
|
112
|
+
function generateRelatedSchema(linkColumn, table, relatedTable, columnName) {
|
|
113
|
+
// generate column for other table
|
|
114
|
+
const relatedSchema = cloneDeep(linkColumn);
|
|
115
|
+
// swap them from the main link
|
|
116
|
+
if (linkColumn.foreignKey) {
|
|
117
|
+
relatedSchema.fieldName = linkColumn.foreignKey;
|
|
118
|
+
relatedSchema.foreignKey = linkColumn.fieldName;
|
|
119
|
+
}
|
|
120
|
+
// is many to many
|
|
121
|
+
else {
|
|
122
|
+
// don't need to copy through, already got it
|
|
123
|
+
relatedSchema.fieldName = linkColumn.throughFrom;
|
|
124
|
+
relatedSchema.throughTo = linkColumn.throughFrom;
|
|
125
|
+
relatedSchema.throughFrom = linkColumn.throughTo;
|
|
126
|
+
}
|
|
127
|
+
relatedSchema.relationshipType = otherRelationshipType(linkColumn.relationshipType);
|
|
128
|
+
relatedSchema.tableId = relatedTable._id;
|
|
129
|
+
relatedSchema.name = columnName;
|
|
130
|
+
table.schema[columnName] = relatedSchema;
|
|
131
|
+
}
|
|
132
|
+
function isRelationshipSetup(column) {
|
|
133
|
+
return column.foreignKey || column.through;
|
|
134
|
+
}
|
|
135
|
+
exports.save = function (ctx) {
|
|
136
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
137
|
+
const appId = ctx.appId;
|
|
138
|
+
const table = ctx.request.body;
|
|
139
|
+
// can't do this right now
|
|
140
|
+
delete table.dataImport;
|
|
141
|
+
const datasourceId = getDatasourceId(ctx.request.body);
|
|
142
|
+
// table doesn't exist already, note that it is created
|
|
143
|
+
if (!table._id) {
|
|
144
|
+
table.created = true;
|
|
145
|
+
}
|
|
146
|
+
let tableToSave = Object.assign({ type: "table", _id: buildExternalTableId(datasourceId, table.name) }, table);
|
|
147
|
+
let oldTable;
|
|
148
|
+
if (ctx.request.body && ctx.request.body._id) {
|
|
149
|
+
oldTable = yield getTable(appId, ctx.request.body._id);
|
|
150
|
+
}
|
|
151
|
+
if (hasTypeChanged(tableToSave, oldTable)) {
|
|
152
|
+
ctx.throw(400, "A column type has changed.");
|
|
153
|
+
}
|
|
154
|
+
const db = new CouchDB(appId);
|
|
155
|
+
const datasource = yield db.get(datasourceId);
|
|
156
|
+
const oldTables = cloneDeep(datasource.entities);
|
|
157
|
+
const tables = datasource.entities;
|
|
158
|
+
const extraTablesToUpdate = [];
|
|
159
|
+
// check if relations need setup
|
|
160
|
+
for (let schema of Object.values(tableToSave.schema)) {
|
|
161
|
+
if (schema.type !== FieldTypes.LINK || isRelationshipSetup(schema)) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const relatedTable = Object.values(tables).find(table => table._id === schema.tableId);
|
|
165
|
+
const relatedColumnName = schema.fieldName;
|
|
166
|
+
const relationType = schema.relationshipType;
|
|
167
|
+
if (relationType === RelationshipTypes.MANY_TO_MANY) {
|
|
168
|
+
const junctionTable = generateManyLinkSchema(datasource, schema, table, relatedTable);
|
|
169
|
+
if (tables[junctionTable.name]) {
|
|
170
|
+
throw "Junction table already exists, cannot create another relationship.";
|
|
171
|
+
}
|
|
172
|
+
tables[junctionTable.name] = junctionTable;
|
|
173
|
+
extraTablesToUpdate.push(junctionTable);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
const fkTable = relationType === RelationshipTypes.ONE_TO_MANY ? table : relatedTable;
|
|
177
|
+
const foreignKey = generateLinkSchema(schema, table, relatedTable, relationType);
|
|
178
|
+
fkTable.schema[foreignKey] = foreignKeyStructure(foreignKey);
|
|
179
|
+
if (fkTable.constrained == null) {
|
|
180
|
+
fkTable.constrained = [];
|
|
181
|
+
}
|
|
182
|
+
if (fkTable.constrained.indexOf(foreignKey) === -1) {
|
|
183
|
+
fkTable.constrained.push(foreignKey);
|
|
184
|
+
}
|
|
185
|
+
// foreign key is in other table, need to save it to external
|
|
186
|
+
if (fkTable._id !== table._id) {
|
|
187
|
+
extraTablesToUpdate.push(fkTable);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
generateRelatedSchema(schema, relatedTable, table, relatedColumnName);
|
|
191
|
+
schema.main = true;
|
|
192
|
+
}
|
|
193
|
+
cleanupRelationships(tableToSave, tables, oldTable);
|
|
194
|
+
const operation = oldTable
|
|
195
|
+
? DataSourceOperation.UPDATE_TABLE
|
|
196
|
+
: DataSourceOperation.CREATE_TABLE;
|
|
197
|
+
yield makeTableRequest(datasource, operation, tableToSave, tables, oldTable);
|
|
198
|
+
// update any extra tables (like foreign keys in other tables)
|
|
199
|
+
for (let extraTable of extraTablesToUpdate) {
|
|
200
|
+
const oldExtraTable = oldTables[extraTable.name];
|
|
201
|
+
let op = oldExtraTable
|
|
202
|
+
? DataSourceOperation.UPDATE_TABLE
|
|
203
|
+
: DataSourceOperation.CREATE_TABLE;
|
|
204
|
+
yield makeTableRequest(datasource, op, extraTable, tables, oldExtraTable);
|
|
205
|
+
}
|
|
206
|
+
// make sure the constrained list, all still exist
|
|
207
|
+
if (Array.isArray(tableToSave.constrained)) {
|
|
208
|
+
tableToSave.constrained = tableToSave.constrained.filter(constraint => Object.keys(tableToSave.schema).includes(constraint));
|
|
209
|
+
}
|
|
210
|
+
// store it into couch now for budibase reference
|
|
211
|
+
datasource.entities[tableToSave.name] = tableToSave;
|
|
212
|
+
yield db.put(datasource);
|
|
213
|
+
return tableToSave;
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
exports.destroy = function (ctx) {
|
|
217
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
+
const appId = ctx.appId;
|
|
219
|
+
const tableToDelete = yield getTable(appId, ctx.params.tableId);
|
|
220
|
+
if (!tableToDelete || !tableToDelete.created) {
|
|
221
|
+
ctx.throw(400, "Cannot delete tables which weren't created in Budibase.");
|
|
222
|
+
}
|
|
223
|
+
const datasourceId = getDatasourceId(tableToDelete);
|
|
224
|
+
const db = new CouchDB(appId);
|
|
225
|
+
const datasource = yield db.get(datasourceId);
|
|
226
|
+
const tables = datasource.entities;
|
|
227
|
+
const operation = DataSourceOperation.DELETE_TABLE;
|
|
228
|
+
yield makeTableRequest(datasource, operation, tableToDelete, tables);
|
|
229
|
+
cleanupRelationships(tableToDelete, tables);
|
|
230
|
+
delete datasource.entities[tableToDelete.name];
|
|
231
|
+
yield db.put(datasource);
|
|
232
|
+
return tableToDelete;
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
exports.bulkImport = function (ctx) {
|
|
236
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
237
|
+
const appId = ctx.appId;
|
|
238
|
+
const table = yield getTable(appId, ctx.params.tableId);
|
|
239
|
+
const { dataImport } = ctx.request.body;
|
|
240
|
+
if (!dataImport || !dataImport.schema || !dataImport.csvString) {
|
|
241
|
+
ctx.throw(400, "Provided data import information is invalid.");
|
|
242
|
+
}
|
|
243
|
+
const rows = yield csvParser.transform(Object.assign(Object.assign({}, dataImport), { existingTable: table }));
|
|
244
|
+
yield handleRequest(appId, DataSourceOperation.BULK_CREATE, table._id, {
|
|
245
|
+
rows,
|
|
246
|
+
});
|
|
247
|
+
return table;
|
|
248
|
+
});
|
|
249
|
+
};
|