@budibase/server 0.9.188 → 0.9.190-alpha.2
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.7d405e74.css +1 -0
- package/builder/assets/index.edea4fa5.js +1316 -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 +1507 -1081
- 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 +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 +11 -8
- 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 +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 +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 +2495 -1737
- 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 +78 -34
- 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 +353 -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 +347 -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 +12 -7
- 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 +13 -8
- 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 +91 -36
- 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 +377 -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 +458 -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
|
@@ -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
|
+
};
|
|
@@ -8,23 +8,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
-
var t = {};
|
|
13
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
-
t[p] = s[p];
|
|
15
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
-
t[p[i]] = s[p[i]];
|
|
19
|
-
}
|
|
20
|
-
return t;
|
|
21
|
-
};
|
|
22
11
|
const CouchDB = require("../../../db");
|
|
23
|
-
const
|
|
12
|
+
const internal = require("./internal");
|
|
13
|
+
const external = require("./external");
|
|
24
14
|
const csvParser = require("../../../utilities/csvParser");
|
|
25
|
-
const {
|
|
26
|
-
const {
|
|
27
|
-
const {
|
|
15
|
+
const { isExternalTable } = require("../../../integrations/utils");
|
|
16
|
+
const { getTableParams, getDatasourceParams, BudibaseInternalDB, } = require("../../../db/utils");
|
|
17
|
+
const { getTable } = require("./utils");
|
|
18
|
+
function pickApi({ tableId, table }) {
|
|
19
|
+
if (table && !tableId) {
|
|
20
|
+
tableId = table._id;
|
|
21
|
+
}
|
|
22
|
+
if (table && table.type === "external") {
|
|
23
|
+
return external;
|
|
24
|
+
}
|
|
25
|
+
else if (tableId && isExternalTable(tableId)) {
|
|
26
|
+
return external;
|
|
27
|
+
}
|
|
28
|
+
return internal;
|
|
29
|
+
}
|
|
30
|
+
// covers both internal and external
|
|
28
31
|
exports.fetch = function (ctx) {
|
|
29
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
30
33
|
const db = new CouchDB(ctx.appId);
|
|
@@ -50,126 +53,49 @@ exports.find = function (ctx) {
|
|
|
50
53
|
exports.save = function (ctx) {
|
|
51
54
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52
55
|
const appId = ctx.appId;
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
let tableToSave = Object.assign({ type: "table", _id: generateTableID(), views: {} }, rest);
|
|
56
|
-
// if the table obj had an _id then it will have been retrieved
|
|
57
|
-
let oldTable;
|
|
58
|
-
if (ctx.request.body && ctx.request.body._id) {
|
|
59
|
-
oldTable = yield db.get(ctx.request.body._id);
|
|
60
|
-
}
|
|
61
|
-
// saving a table is a complex operation, involving many different steps, this
|
|
62
|
-
// has been broken out into a utility to make it more obvious/easier to manipulate
|
|
63
|
-
const tableSaveFunctions = new TableSaveFunctions({
|
|
64
|
-
db,
|
|
65
|
-
ctx,
|
|
66
|
-
oldTable,
|
|
67
|
-
dataImport,
|
|
68
|
-
});
|
|
69
|
-
tableToSave = yield tableSaveFunctions.before(tableToSave);
|
|
70
|
-
// make sure that types don't change of a column, have to remove
|
|
71
|
-
// the column if you want to change the type
|
|
72
|
-
if (oldTable && oldTable.schema) {
|
|
73
|
-
for (let propKey of Object.keys(tableToSave.schema)) {
|
|
74
|
-
let column = tableToSave.schema[propKey];
|
|
75
|
-
let oldColumn = oldTable.schema[propKey];
|
|
76
|
-
if (oldColumn && oldColumn.type === "internal") {
|
|
77
|
-
oldColumn.type = "auto";
|
|
78
|
-
}
|
|
79
|
-
if (oldColumn && oldColumn.type !== column.type) {
|
|
80
|
-
ctx.throw(400, "Cannot change the type of a column");
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
// Don't rename if the name is the same
|
|
85
|
-
let { _rename } = tableToSave;
|
|
86
|
-
/* istanbul ignore next */
|
|
87
|
-
if (_rename && _rename.old === _rename.updated) {
|
|
88
|
-
_rename = null;
|
|
89
|
-
delete tableToSave._rename;
|
|
90
|
-
}
|
|
91
|
-
// rename row fields when table column is renamed
|
|
92
|
-
/* istanbul ignore next */
|
|
93
|
-
if (_rename && tableToSave.schema[_rename.updated].type === FieldTypes.LINK) {
|
|
94
|
-
ctx.throw(400, "Cannot rename a linked column.");
|
|
95
|
-
}
|
|
96
|
-
tableToSave = yield tableSaveFunctions.mid(tableToSave);
|
|
97
|
-
// update schema of non-statistics views when new columns are added
|
|
98
|
-
for (let view in tableToSave.views) {
|
|
99
|
-
const tableView = tableToSave.views[view];
|
|
100
|
-
if (!tableView)
|
|
101
|
-
continue;
|
|
102
|
-
if (tableView.schema.group || tableView.schema.field)
|
|
103
|
-
continue;
|
|
104
|
-
tableView.schema = tableToSave.schema;
|
|
105
|
-
}
|
|
106
|
-
// update linked rows
|
|
107
|
-
try {
|
|
108
|
-
const linkResp = yield linkRows.updateLinks({
|
|
109
|
-
appId,
|
|
110
|
-
eventType: oldTable
|
|
111
|
-
? linkRows.EventType.TABLE_UPDATED
|
|
112
|
-
: linkRows.EventType.TABLE_SAVE,
|
|
113
|
-
table: tableToSave,
|
|
114
|
-
oldTable: oldTable,
|
|
115
|
-
});
|
|
116
|
-
if (linkResp != null && linkResp._rev) {
|
|
117
|
-
tableToSave._rev = linkResp._rev;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
ctx.throw(400, err);
|
|
122
|
-
}
|
|
123
|
-
// don't perform any updates until relationships have been
|
|
124
|
-
// checked by the updateLinks function
|
|
125
|
-
const updatedRows = tableSaveFunctions.getUpdatedRows();
|
|
126
|
-
if (updatedRows && updatedRows.length !== 0) {
|
|
127
|
-
yield db.bulkDocs(updatedRows);
|
|
128
|
-
}
|
|
129
|
-
const result = yield db.put(tableToSave);
|
|
130
|
-
tableToSave._rev = result.rev;
|
|
131
|
-
tableToSave = yield tableSaveFunctions.after(tableToSave);
|
|
132
|
-
ctx.eventEmitter &&
|
|
133
|
-
ctx.eventEmitter.emitTable(`table:save`, appId, tableToSave);
|
|
56
|
+
const table = ctx.request.body;
|
|
57
|
+
const savedTable = yield pickApi({ table }).save(ctx);
|
|
134
58
|
ctx.status = 200;
|
|
135
|
-
ctx.message = `Table ${
|
|
136
|
-
ctx.
|
|
59
|
+
ctx.message = `Table ${table.name} saved successfully.`;
|
|
60
|
+
ctx.eventEmitter &&
|
|
61
|
+
ctx.eventEmitter.emitTable(`table:save`, appId, savedTable);
|
|
62
|
+
ctx.body = savedTable;
|
|
137
63
|
});
|
|
138
64
|
};
|
|
139
65
|
exports.destroy = function (ctx) {
|
|
140
66
|
return __awaiter(this, void 0, void 0, function* () {
|
|
141
67
|
const appId = ctx.appId;
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
// Delete all rows for that table
|
|
145
|
-
const rows = yield db.allDocs(getRowParams(ctx.params.tableId, null, {
|
|
146
|
-
include_docs: true,
|
|
147
|
-
}));
|
|
148
|
-
yield db.bulkDocs(rows.rows.map(row => (Object.assign(Object.assign({}, row.doc), { _deleted: true }))));
|
|
149
|
-
// update linked rows
|
|
150
|
-
yield linkRows.updateLinks({
|
|
151
|
-
appId,
|
|
152
|
-
eventType: linkRows.EventType.TABLE_DELETE,
|
|
153
|
-
table: tableToDelete,
|
|
154
|
-
});
|
|
155
|
-
// don't remove the table itself until very end
|
|
156
|
-
yield db.remove(tableToDelete);
|
|
157
|
-
// remove table search index
|
|
158
|
-
const currentIndexes = yield db.getIndexes();
|
|
159
|
-
const existingIndex = currentIndexes.indexes.find(existing => existing.name === `search:${ctx.params.tableId}`);
|
|
160
|
-
if (existingIndex) {
|
|
161
|
-
yield db.deleteIndex(existingIndex);
|
|
162
|
-
}
|
|
68
|
+
const tableId = ctx.params.tableId;
|
|
69
|
+
const deletedTable = yield pickApi({ tableId }).destroy(ctx);
|
|
163
70
|
ctx.eventEmitter &&
|
|
164
|
-
ctx.eventEmitter.emitTable(`table:delete`, appId,
|
|
71
|
+
ctx.eventEmitter.emitTable(`table:delete`, appId, deletedTable);
|
|
165
72
|
ctx.status = 200;
|
|
166
|
-
ctx.body = { message: `Table ${
|
|
73
|
+
ctx.body = { message: `Table ${tableId} deleted.` };
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
exports.bulkImport = function (ctx) {
|
|
77
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
const tableId = ctx.params.tableId;
|
|
79
|
+
yield pickApi({ tableId }).bulkImport(ctx);
|
|
80
|
+
// right now we don't trigger anything for bulk import because it
|
|
81
|
+
// can only be done in the builder, but in the future we may need to
|
|
82
|
+
// think about events for bulk items
|
|
83
|
+
ctx.status = 200;
|
|
84
|
+
ctx.body = { message: `Bulk rows created.` };
|
|
167
85
|
});
|
|
168
86
|
};
|
|
169
87
|
exports.validateCSVSchema = function (ctx) {
|
|
170
88
|
return __awaiter(this, void 0, void 0, function* () {
|
|
171
|
-
|
|
172
|
-
const
|
|
89
|
+
// tableId being specified means its an import to an existing table
|
|
90
|
+
const { csvString, schema = {}, tableId } = ctx.request.body;
|
|
91
|
+
let existingTable;
|
|
92
|
+
if (tableId) {
|
|
93
|
+
existingTable = yield getTable(ctx.appId, tableId);
|
|
94
|
+
}
|
|
95
|
+
let result = yield csvParser.parse(csvString, schema);
|
|
96
|
+
if (existingTable) {
|
|
97
|
+
result = csvParser.updateSchema({ schema: result, existingTable });
|
|
98
|
+
}
|
|
173
99
|
ctx.body = { schema: result };
|
|
174
100
|
});
|
|
175
101
|
};
|
|
@@ -0,0 +1,150 @@
|
|
|
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
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
+
var t = {};
|
|
13
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
+
t[p] = s[p];
|
|
15
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
+
t[p[i]] = s[p[i]];
|
|
19
|
+
}
|
|
20
|
+
return t;
|
|
21
|
+
};
|
|
22
|
+
const CouchDB = require("../../../db");
|
|
23
|
+
const linkRows = require("../../../db/linkedRows");
|
|
24
|
+
const { getRowParams, generateTableID } = require("../../../db/utils");
|
|
25
|
+
const { FieldTypes } = require("../../../constants");
|
|
26
|
+
const { TableSaveFunctions, hasTypeChanged, getTable, handleDataImport, } = require("./utils");
|
|
27
|
+
exports.save = function (ctx) {
|
|
28
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
const appId = ctx.appId;
|
|
30
|
+
const db = new CouchDB(appId);
|
|
31
|
+
const _a = ctx.request.body, { dataImport } = _a, rest = __rest(_a, ["dataImport"]);
|
|
32
|
+
let tableToSave = Object.assign({ type: "table", _id: generateTableID(), views: {} }, rest);
|
|
33
|
+
// if the table obj had an _id then it will have been retrieved
|
|
34
|
+
let oldTable;
|
|
35
|
+
if (ctx.request.body && ctx.request.body._id) {
|
|
36
|
+
oldTable = yield db.get(ctx.request.body._id);
|
|
37
|
+
}
|
|
38
|
+
if (hasTypeChanged(tableToSave, oldTable)) {
|
|
39
|
+
ctx.throw(400, "A column type has changed.");
|
|
40
|
+
}
|
|
41
|
+
// saving a table is a complex operation, involving many different steps, this
|
|
42
|
+
// has been broken out into a utility to make it more obvious/easier to manipulate
|
|
43
|
+
const tableSaveFunctions = new TableSaveFunctions({
|
|
44
|
+
db,
|
|
45
|
+
ctx,
|
|
46
|
+
oldTable,
|
|
47
|
+
dataImport,
|
|
48
|
+
});
|
|
49
|
+
tableToSave = yield tableSaveFunctions.before(tableToSave);
|
|
50
|
+
// make sure that types don't change of a column, have to remove
|
|
51
|
+
// the column if you want to change the type
|
|
52
|
+
if (oldTable && oldTable.schema) {
|
|
53
|
+
for (let propKey of Object.keys(tableToSave.schema)) {
|
|
54
|
+
let column = tableToSave.schema[propKey];
|
|
55
|
+
let oldColumn = oldTable.schema[propKey];
|
|
56
|
+
if (oldColumn && oldColumn.type === "internal") {
|
|
57
|
+
oldColumn.type = "auto";
|
|
58
|
+
}
|
|
59
|
+
if (oldColumn && oldColumn.type !== column.type) {
|
|
60
|
+
ctx.throw(400, "Cannot change the type of a column");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Don't rename if the name is the same
|
|
65
|
+
let { _rename } = tableToSave;
|
|
66
|
+
/* istanbul ignore next */
|
|
67
|
+
if (_rename && _rename.old === _rename.updated) {
|
|
68
|
+
_rename = null;
|
|
69
|
+
delete tableToSave._rename;
|
|
70
|
+
}
|
|
71
|
+
// rename row fields when table column is renamed
|
|
72
|
+
/* istanbul ignore next */
|
|
73
|
+
if (_rename && tableToSave.schema[_rename.updated].type === FieldTypes.LINK) {
|
|
74
|
+
ctx.throw(400, "Cannot rename a linked column.");
|
|
75
|
+
}
|
|
76
|
+
tableToSave = yield tableSaveFunctions.mid(tableToSave);
|
|
77
|
+
// update schema of non-statistics views when new columns are added
|
|
78
|
+
for (let view in tableToSave.views) {
|
|
79
|
+
const tableView = tableToSave.views[view];
|
|
80
|
+
if (!tableView)
|
|
81
|
+
continue;
|
|
82
|
+
if (tableView.schema.group || tableView.schema.field)
|
|
83
|
+
continue;
|
|
84
|
+
tableView.schema = tableToSave.schema;
|
|
85
|
+
}
|
|
86
|
+
// update linked rows
|
|
87
|
+
try {
|
|
88
|
+
const linkResp = yield linkRows.updateLinks({
|
|
89
|
+
appId,
|
|
90
|
+
eventType: oldTable
|
|
91
|
+
? linkRows.EventType.TABLE_UPDATED
|
|
92
|
+
: linkRows.EventType.TABLE_SAVE,
|
|
93
|
+
table: tableToSave,
|
|
94
|
+
oldTable: oldTable,
|
|
95
|
+
});
|
|
96
|
+
if (linkResp != null && linkResp._rev) {
|
|
97
|
+
tableToSave._rev = linkResp._rev;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
ctx.throw(400, err);
|
|
102
|
+
}
|
|
103
|
+
// don't perform any updates until relationships have been
|
|
104
|
+
// checked by the updateLinks function
|
|
105
|
+
const updatedRows = tableSaveFunctions.getUpdatedRows();
|
|
106
|
+
if (updatedRows && updatedRows.length !== 0) {
|
|
107
|
+
yield db.bulkDocs(updatedRows);
|
|
108
|
+
}
|
|
109
|
+
const result = yield db.put(tableToSave);
|
|
110
|
+
tableToSave._rev = result.rev;
|
|
111
|
+
tableToSave = yield tableSaveFunctions.after(tableToSave);
|
|
112
|
+
return tableToSave;
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
exports.destroy = function (ctx) {
|
|
116
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
117
|
+
const appId = ctx.appId;
|
|
118
|
+
const db = new CouchDB(appId);
|
|
119
|
+
const tableToDelete = yield db.get(ctx.params.tableId);
|
|
120
|
+
// Delete all rows for that table
|
|
121
|
+
const rows = yield db.allDocs(getRowParams(ctx.params.tableId, null, {
|
|
122
|
+
include_docs: true,
|
|
123
|
+
}));
|
|
124
|
+
yield db.bulkDocs(rows.rows.map(row => (Object.assign(Object.assign({}, row.doc), { _deleted: true }))));
|
|
125
|
+
// update linked rows
|
|
126
|
+
yield linkRows.updateLinks({
|
|
127
|
+
appId,
|
|
128
|
+
eventType: linkRows.EventType.TABLE_DELETE,
|
|
129
|
+
table: tableToDelete,
|
|
130
|
+
});
|
|
131
|
+
// don't remove the table itself until very end
|
|
132
|
+
yield db.remove(tableToDelete);
|
|
133
|
+
// remove table search index
|
|
134
|
+
const currentIndexes = yield db.getIndexes();
|
|
135
|
+
const existingIndex = currentIndexes.indexes.find(existing => existing.name === `search:${ctx.params.tableId}`);
|
|
136
|
+
if (existingIndex) {
|
|
137
|
+
yield db.deleteIndex(existingIndex);
|
|
138
|
+
}
|
|
139
|
+
return tableToDelete;
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
exports.bulkImport = function (ctx) {
|
|
143
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
144
|
+
const appId = ctx.appId;
|
|
145
|
+
const table = yield getTable(appId, ctx.params.tableId);
|
|
146
|
+
const { dataImport } = ctx.request.body;
|
|
147
|
+
yield handleDataImport(appId, ctx.user, table, dataImport);
|
|
148
|
+
return table;
|
|
149
|
+
});
|
|
150
|
+
};
|