@budibase/server 0.9.174 → 0.9.176-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/builder/assets/{index.7469e1e4.css → index.75ed4773.css} +1 -1
- package/builder/assets/{index.ba2741f9.js → index.d3780441.js} +34 -34
- package/builder/index.html +2 -2
- package/coverage/clover.xml +383 -207
- package/coverage/coverage-final.json +8 -6
- package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
- package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/controllers/application.js.html +1 -1
- package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
- package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
- package/coverage/lcov-report/api/controllers/component.js.html +1 -1
- package/coverage/lcov-report/api/controllers/datasource.js.html +120 -24
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +19 -19
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query.js.html +9 -3
- package/coverage/lcov-report/api/controllers/role.js.html +1 -1
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/index.html +14 -14
- package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +11 -32
- package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
- package/coverage/lcov-report/api/controllers/script.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/external.js.html +908 -0
- package/coverage/lcov-report/api/controllers/table/index.html +59 -29
- package/coverage/lcov-report/api/controllers/table/index.js.html +52 -376
- package/coverage/lcov-report/api/controllers/table/internal.js.html +494 -0
- package/coverage/lcov-report/api/controllers/table/utils.js.html +70 -10
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
- package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +1 -1
- package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
- package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/routes/application.js.html +1 -1
- package/coverage/lcov-report/api/routes/auth.js.html +1 -1
- package/coverage/lcov-report/api/routes/automation.js.html +1 -1
- package/coverage/lcov-report/api/routes/backup.js.html +1 -1
- package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
- package/coverage/lcov-report/api/routes/component.js.html +1 -1
- package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
- package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
- package/coverage/lcov-report/api/routes/dev.js.html +1 -1
- package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
- package/coverage/lcov-report/api/routes/index.html +1 -1
- package/coverage/lcov-report/api/routes/index.js.html +1 -1
- package/coverage/lcov-report/api/routes/integration.js.html +1 -1
- package/coverage/lcov-report/api/routes/layout.js.html +1 -1
- package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
- package/coverage/lcov-report/api/routes/permission.js.html +1 -1
- package/coverage/lcov-report/api/routes/query.js.html +1 -1
- package/coverage/lcov-report/api/routes/role.js.html +1 -1
- package/coverage/lcov-report/api/routes/routing.js.html +1 -1
- package/coverage/lcov-report/api/routes/row.js.html +1 -1
- package/coverage/lcov-report/api/routes/screen.js.html +1 -1
- package/coverage/lcov-report/api/routes/script.js.html +1 -1
- package/coverage/lcov-report/api/routes/static.js.html +1 -1
- package/coverage/lcov-report/api/routes/table.js.html +1 -1
- package/coverage/lcov-report/api/routes/templates.js.html +1 -1
- package/coverage/lcov-report/api/routes/user.js.html +1 -1
- package/coverage/lcov-report/api/routes/view.js.html +1 -1
- package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/actions.js.html +1 -1
- package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
- package/coverage/lcov-report/automations/bullboard.js.html +1 -1
- package/coverage/lcov-report/automations/index.html +1 -1
- package/coverage/lcov-report/automations/index.js.html +1 -1
- package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
- package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
- package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
- package/coverage/lcov-report/automations/steps/index.html +1 -1
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
- package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
- package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
- package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
- package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/thread.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/triggers.js.html +1 -1
- package/coverage/lcov-report/automations/utils.js.html +1 -1
- package/coverage/lcov-report/constants/index.html +5 -5
- package/coverage/lcov-report/constants/index.js.html +25 -4
- package/coverage/lcov-report/constants/layouts.js.html +1 -1
- package/coverage/lcov-report/constants/screens.js.html +1 -1
- package/coverage/lcov-report/db/client.js.html +1 -1
- package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +1 -1
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
- package/coverage/lcov-report/db/newid.js.html +1 -1
- package/coverage/lcov-report/db/utils.js.html +1 -1
- package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
- package/coverage/lcov-report/events/index.html +1 -1
- package/coverage/lcov-report/events/index.js.html +1 -1
- package/coverage/lcov-report/events/utils.js.html +1 -1
- package/coverage/lcov-report/index.html +38 -38
- package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
- package/coverage/lcov-report/integrations/tests/index.html +1 -1
- package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
- package/coverage/lcov-report/middleware/authorized.js.html +1 -1
- package/coverage/lcov-report/middleware/builder.js.html +1 -1
- package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
- package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
- package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
- package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
- package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
- package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
- package/coverage/lcov-report/utilities/global.js.html +1 -1
- package/coverage/lcov-report/utilities/index.html +1 -1
- package/coverage/lcov-report/utilities/index.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
- package/coverage/lcov-report/utilities/security.js.html +1 -1
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +1 -1
- package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
- package/coverage/lcov.info +652 -332
- package/dist/api/controllers/datasource.js +41 -14
- package/dist/api/controllers/query.js +3 -1
- package/dist/api/controllers/row/ExternalRequest.js +12 -10
- package/dist/api/controllers/row/utils.js +3 -11
- package/dist/api/controllers/table/external.js +222 -0
- package/dist/api/controllers/table/index.js +28 -121
- package/dist/api/controllers/table/internal.js +138 -0
- package/dist/api/controllers/table/utils.js +17 -0
- package/dist/constants/index.js +6 -0
- package/dist/definitions/datasource.js +3 -0
- package/dist/integrations/base/datasourcePlus.js +2 -0
- package/dist/integrations/base/sql.js +16 -11
- package/dist/integrations/base/sqlTable.js +141 -0
- package/dist/integrations/base/utils.js +30 -0
- package/dist/integrations/mysql.js +13 -7
- package/dist/integrations/postgres.js +18 -8
- package/dist/integrations/utils.js +21 -6
- package/dist/package.json +4 -4
- package/dist/tests/utilities/TestConfiguration.js +2 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/api/controllers/datasource.js +46 -14
- package/src/api/controllers/query.js +3 -1
- package/src/api/controllers/row/ExternalRequest.ts +12 -10
- package/src/api/controllers/row/utils.js +3 -10
- package/src/api/controllers/table/external.js +276 -0
- package/src/api/controllers/table/index.js +27 -135
- package/src/api/controllers/table/internal.js +138 -0
- package/src/api/controllers/table/utils.js +20 -0
- package/src/api/routes/tests/datasource.spec.js +2 -2
- package/src/api/routes/tests/query.spec.js +0 -1
- package/src/constants/index.js +7 -0
- package/src/definitions/common.ts +7 -1
- package/src/definitions/datasource.ts +5 -0
- package/src/integrations/base/datasourcePlus.ts +8 -0
- package/src/integrations/base/sql.ts +15 -16
- package/src/integrations/base/sqlTable.ts +167 -0
- package/src/integrations/base/utils.ts +19 -0
- package/src/integrations/mysql.ts +15 -9
- package/src/integrations/postgres.ts +19 -9
- package/src/integrations/utils.ts +22 -6
- package/src/tests/utilities/TestConfiguration.js +2 -1
|
@@ -10,8 +10,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
const CouchDB = require("../../db");
|
|
12
12
|
const { generateDatasourceID, getDatasourceParams, getQueryParams, DocumentTypes, BudibaseInternalDB, getTableParams, } = require("../../db/utils");
|
|
13
|
+
const { BuildSchemaErrors } = require("../../constants");
|
|
13
14
|
const { integrations } = require("../../integrations");
|
|
14
|
-
const {
|
|
15
|
+
const { getDatasourceAndQuery } = require("./row/utils");
|
|
15
16
|
exports.fetch = function (ctx) {
|
|
16
17
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17
18
|
const database = new CouchDB(ctx.appId);
|
|
@@ -33,11 +34,15 @@ exports.buildSchemaFromDb = function (ctx) {
|
|
|
33
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
34
35
|
const db = new CouchDB(ctx.appId);
|
|
35
36
|
const datasource = yield db.get(ctx.params.datasourceId);
|
|
36
|
-
const tables = yield buildSchemaHelper(datasource);
|
|
37
|
+
const { tables, error } = yield buildSchemaHelper(datasource);
|
|
37
38
|
datasource.entities = tables;
|
|
38
|
-
const
|
|
39
|
-
datasource._rev =
|
|
40
|
-
|
|
39
|
+
const dbResp = yield db.put(datasource);
|
|
40
|
+
datasource._rev = dbResp.rev;
|
|
41
|
+
const response = { datasource };
|
|
42
|
+
if (error) {
|
|
43
|
+
response.error = error;
|
|
44
|
+
}
|
|
45
|
+
ctx.body = response;
|
|
41
46
|
});
|
|
42
47
|
};
|
|
43
48
|
exports.update = function (ctx) {
|
|
@@ -57,7 +62,7 @@ exports.update = function (ctx) {
|
|
|
57
62
|
}
|
|
58
63
|
ctx.status = 200;
|
|
59
64
|
ctx.message = "Datasource saved successfully.";
|
|
60
|
-
ctx.body = datasource;
|
|
65
|
+
ctx.body = { datasource };
|
|
61
66
|
});
|
|
62
67
|
};
|
|
63
68
|
exports.save = function (ctx) {
|
|
@@ -66,12 +71,14 @@ exports.save = function (ctx) {
|
|
|
66
71
|
const plus = ctx.request.body.datasource.plus;
|
|
67
72
|
const fetchSchema = ctx.request.body.fetchSchema;
|
|
68
73
|
const datasource = Object.assign({ _id: generateDatasourceID({ plus }), type: plus ? DocumentTypes.DATASOURCE_PLUS : DocumentTypes.DATASOURCE }, ctx.request.body.datasource);
|
|
74
|
+
let schemaError = null;
|
|
69
75
|
if (fetchSchema) {
|
|
70
|
-
|
|
76
|
+
const { tables, error } = yield buildSchemaHelper(datasource);
|
|
77
|
+
schemaError = error;
|
|
71
78
|
datasource.entities = tables;
|
|
72
79
|
}
|
|
73
|
-
const
|
|
74
|
-
datasource._rev =
|
|
80
|
+
const dbResp = yield db.put(datasource);
|
|
81
|
+
datasource._rev = dbResp.rev;
|
|
75
82
|
// Drain connection pools when configuration is changed
|
|
76
83
|
if (datasource.source) {
|
|
77
84
|
const source = integrations[datasource.source];
|
|
@@ -79,9 +86,11 @@ exports.save = function (ctx) {
|
|
|
79
86
|
yield source.pool.end();
|
|
80
87
|
}
|
|
81
88
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
const response = { datasource };
|
|
90
|
+
if (schemaError) {
|
|
91
|
+
response.error = schemaError;
|
|
92
|
+
}
|
|
93
|
+
ctx.body = response;
|
|
85
94
|
});
|
|
86
95
|
};
|
|
87
96
|
exports.destroy = function (ctx) {
|
|
@@ -107,7 +116,7 @@ exports.query = function (ctx) {
|
|
|
107
116
|
return __awaiter(this, void 0, void 0, function* () {
|
|
108
117
|
const queryJson = ctx.request.body;
|
|
109
118
|
try {
|
|
110
|
-
ctx.body = yield
|
|
119
|
+
ctx.body = yield getDatasourceAndQuery(ctx.appId, queryJson);
|
|
111
120
|
}
|
|
112
121
|
catch (err) {
|
|
113
122
|
ctx.throw(400, err);
|
|
@@ -120,5 +129,23 @@ const buildSchemaHelper = (datasource) => __awaiter(void 0, void 0, void 0, func
|
|
|
120
129
|
const connector = new Connector(datasource.config);
|
|
121
130
|
yield connector.buildSchema(datasource._id, datasource.entities);
|
|
122
131
|
datasource.entities = connector.tables;
|
|
123
|
-
|
|
132
|
+
// make sure they all have a display name selected
|
|
133
|
+
for (let entity of Object.values(datasource.entities)) {
|
|
134
|
+
if (entity.primaryDisplay) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const notAutoColumn = Object.values(entity.schema).find(schema => !schema.autocolumn);
|
|
138
|
+
if (notAutoColumn) {
|
|
139
|
+
entity.primaryDisplay = notAutoColumn.name;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const errors = connector.schemaErrors;
|
|
143
|
+
let error = null;
|
|
144
|
+
if (errors && Object.keys(errors).length > 0) {
|
|
145
|
+
const noKeyTables = Object.entries(errors)
|
|
146
|
+
.filter(entry => entry[1] === BuildSchemaErrors.NO_KEY)
|
|
147
|
+
.map(([name]) => name);
|
|
148
|
+
error = `No primary key constraint found for the following: ${noKeyTables.join(", ")}`;
|
|
149
|
+
}
|
|
150
|
+
return { tables: connector.tables, error };
|
|
124
151
|
});
|
|
@@ -95,7 +95,9 @@ function enrichQueryFields(fields, parameters = {}) {
|
|
|
95
95
|
}
|
|
96
96
|
else if (typeof fields[key] === "string") {
|
|
97
97
|
// enrich string value as normal
|
|
98
|
-
enrichedQuery[key] = yield processString(fields[key], parameters
|
|
98
|
+
enrichedQuery[key] = yield processString(fields[key], parameters, {
|
|
99
|
+
noHelpers: true,
|
|
100
|
+
});
|
|
99
101
|
}
|
|
100
102
|
else {
|
|
101
103
|
enrichedQuery[key] = fields[key];
|
|
@@ -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
|
|
@@ -182,7 +183,7 @@ var External;
|
|
|
182
183
|
let newRow = {}, manyRelationships = [];
|
|
183
184
|
for (let [key, field] of Object.entries(table.schema)) {
|
|
184
185
|
// if set already, or not set just skip it
|
|
185
|
-
if (
|
|
186
|
+
if (row[key] == null || newRow[key] || field.autocolumn || field.type === FieldTypes.FORMULA) {
|
|
186
187
|
continue;
|
|
187
188
|
}
|
|
188
189
|
// if its an empty string then it means return the column to null (if possible)
|
|
@@ -295,7 +296,7 @@ var External;
|
|
|
295
296
|
// do this at end once its been added to the final rows
|
|
296
297
|
finalRows = this.updateRelationshipColumns(row, finalRows, relationships);
|
|
297
298
|
}
|
|
298
|
-
return Object.values(finalRows);
|
|
299
|
+
return processFormulas(table, Object.values(finalRows));
|
|
299
300
|
}
|
|
300
301
|
/**
|
|
301
302
|
* Gets the list of relationship JSON structures based on the columns in the table,
|
|
@@ -359,7 +360,7 @@ var External;
|
|
|
359
360
|
const tableId = isMany ? field.through : field.tableId;
|
|
360
361
|
const manyKey = field.throughFrom || primaryKey;
|
|
361
362
|
const fieldName = isMany ? manyKey : field.fieldName;
|
|
362
|
-
const response = yield
|
|
363
|
+
const response = yield getDatasourceAndQuery(this.appId, {
|
|
363
364
|
endpoint: getEndpoint(tableId, DataSourceOperation.READ),
|
|
364
365
|
filters: {
|
|
365
366
|
equal: {
|
|
@@ -403,7 +404,7 @@ var External;
|
|
|
403
404
|
? DataSourceOperation.UPDATE
|
|
404
405
|
: DataSourceOperation.CREATE;
|
|
405
406
|
if (!found) {
|
|
406
|
-
promises.push(
|
|
407
|
+
promises.push(getDatasourceAndQuery(appId, {
|
|
407
408
|
endpoint: getEndpoint(tableId, operation),
|
|
408
409
|
// if we're doing many relationships then we're writing, only one response
|
|
409
410
|
body,
|
|
@@ -430,7 +431,7 @@ var External;
|
|
|
430
431
|
? DataSourceOperation.DELETE
|
|
431
432
|
: DataSourceOperation.UPDATE;
|
|
432
433
|
const body = isMany ? null : { [colName]: null };
|
|
433
|
-
promises.push(
|
|
434
|
+
promises.push(getDatasourceAndQuery(this.appId, {
|
|
434
435
|
endpoint: getEndpoint(tableId, op),
|
|
435
436
|
body,
|
|
436
437
|
filters,
|
|
@@ -449,13 +450,14 @@ var External;
|
|
|
449
450
|
* is more performant and has the added benefit of protecting against this scenario.
|
|
450
451
|
*/
|
|
451
452
|
buildFields(table, includeRelations = datasource_1.IncludeRelationships.INCLUDE) {
|
|
452
|
-
function
|
|
453
|
+
function extractRealFields(table, existing = []) {
|
|
453
454
|
return Object.entries(table.schema)
|
|
454
455
|
.filter(column => column[1].type !== FieldTypes.LINK &&
|
|
456
|
+
column[1].type !== FieldTypes.FORMULA &&
|
|
455
457
|
!existing.find((field) => field === column[0]))
|
|
456
458
|
.map(column => `${table.name}.${column[0]}`);
|
|
457
459
|
}
|
|
458
|
-
let fields =
|
|
460
|
+
let fields = extractRealFields(table);
|
|
459
461
|
for (let field of Object.values(table.schema)) {
|
|
460
462
|
if (field.type !== FieldTypes.LINK || !includeRelations) {
|
|
461
463
|
continue;
|
|
@@ -463,7 +465,7 @@ var External;
|
|
|
463
465
|
const { tableName: linkTableName } = breakExternalTableId(field.tableId);
|
|
464
466
|
const linkTable = this.tables[linkTableName];
|
|
465
467
|
if (linkTable) {
|
|
466
|
-
const linkedFields =
|
|
468
|
+
const linkedFields = extractRealFields(linkTable, fields);
|
|
467
469
|
fields = fields.concat(linkedFields);
|
|
468
470
|
}
|
|
469
471
|
}
|
|
@@ -521,7 +523,7 @@ var External;
|
|
|
521
523
|
},
|
|
522
524
|
};
|
|
523
525
|
// can't really use response right now
|
|
524
|
-
const response = yield
|
|
526
|
+
const response = yield getDatasourceAndQuery(appId, json);
|
|
525
527
|
// handle many to many relationships now if we know the ID (could be auto increment)
|
|
526
528
|
if (operation !== DataSourceOperation.READ &&
|
|
527
529
|
processed.manyRelationships) {
|
|
@@ -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;
|
|
@@ -0,0 +1,222 @@
|
|
|
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, } = require("./utils");
|
|
14
|
+
const { DataSourceOperation, FieldTypes, RelationshipTypes, } = require("../../../constants");
|
|
15
|
+
const { makeExternalQuery } = require("../../../integrations/base/utils");
|
|
16
|
+
const { cloneDeep } = require("lodash/fp");
|
|
17
|
+
function makeTableRequest(datasource, operation, table, tables, oldTable = null) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
const json = {
|
|
20
|
+
endpoint: {
|
|
21
|
+
datasourceId: datasource._id,
|
|
22
|
+
entityId: table._id,
|
|
23
|
+
operation,
|
|
24
|
+
},
|
|
25
|
+
meta: {
|
|
26
|
+
tables,
|
|
27
|
+
},
|
|
28
|
+
table,
|
|
29
|
+
};
|
|
30
|
+
if (oldTable) {
|
|
31
|
+
json.meta.table = oldTable;
|
|
32
|
+
}
|
|
33
|
+
return makeExternalQuery(datasource, json);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function cleanupRelationships(table, tables, oldTable = null) {
|
|
37
|
+
const tableToIterate = oldTable ? oldTable : table;
|
|
38
|
+
// clean up relationships in couch table schemas
|
|
39
|
+
for (let [key, schema] of Object.entries(tableToIterate.schema)) {
|
|
40
|
+
if (schema.type === FieldTypes.LINK &&
|
|
41
|
+
(!oldTable || table.schema[key] == null)) {
|
|
42
|
+
const relatedTable = Object.values(tables).find(table => table._id === schema.tableId);
|
|
43
|
+
const foreignKey = schema.foreignKey;
|
|
44
|
+
if (!relatedTable || !foreignKey) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
for (let [relatedKey, relatedSchema] of Object.entries(relatedTable.schema)) {
|
|
48
|
+
if (relatedSchema.type === FieldTypes.LINK &&
|
|
49
|
+
relatedSchema.fieldName === foreignKey) {
|
|
50
|
+
delete relatedTable.schema[relatedKey];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function getDatasourceId(table) {
|
|
57
|
+
if (!table) {
|
|
58
|
+
throw "No table supplied";
|
|
59
|
+
}
|
|
60
|
+
if (table.sourceId) {
|
|
61
|
+
return table.sourceId;
|
|
62
|
+
}
|
|
63
|
+
return breakExternalTableId(table._id).datasourceId;
|
|
64
|
+
}
|
|
65
|
+
function otherRelationshipType(type) {
|
|
66
|
+
if (type === RelationshipTypes.MANY_TO_MANY) {
|
|
67
|
+
return RelationshipTypes.MANY_TO_MANY;
|
|
68
|
+
}
|
|
69
|
+
return type === RelationshipTypes.ONE_TO_MANY
|
|
70
|
+
? RelationshipTypes.MANY_TO_ONE
|
|
71
|
+
: RelationshipTypes.ONE_TO_MANY;
|
|
72
|
+
}
|
|
73
|
+
function generateManyLinkSchema(datasource, column, table, relatedTable) {
|
|
74
|
+
const primary = table.name + table.primary[0];
|
|
75
|
+
const relatedPrimary = relatedTable.name + relatedTable.primary[0];
|
|
76
|
+
const jcTblName = generateJunctionTableName(column, table, relatedTable);
|
|
77
|
+
// first create the new table
|
|
78
|
+
const junctionTable = {
|
|
79
|
+
_id: buildExternalTableId(datasource._id, jcTblName),
|
|
80
|
+
name: jcTblName,
|
|
81
|
+
primary: [primary, relatedPrimary],
|
|
82
|
+
constrained: [primary, relatedPrimary],
|
|
83
|
+
schema: {
|
|
84
|
+
[primary]: foreignKeyStructure(primary, {
|
|
85
|
+
toTable: table.name,
|
|
86
|
+
toKey: table.primary[0],
|
|
87
|
+
}),
|
|
88
|
+
[relatedPrimary]: foreignKeyStructure(relatedPrimary, {
|
|
89
|
+
toTable: relatedTable.name,
|
|
90
|
+
toKey: relatedTable.primary[0],
|
|
91
|
+
}),
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
column.through = junctionTable._id;
|
|
95
|
+
column.throughFrom = primary;
|
|
96
|
+
column.throughTo = relatedPrimary;
|
|
97
|
+
column.fieldName = relatedPrimary;
|
|
98
|
+
return junctionTable;
|
|
99
|
+
}
|
|
100
|
+
function generateLinkSchema(column, table, relatedTable, type) {
|
|
101
|
+
const isOneSide = type === RelationshipTypes.ONE_TO_MANY;
|
|
102
|
+
const primary = isOneSide ? relatedTable.primary[0] : table.primary[0];
|
|
103
|
+
// generate a foreign key
|
|
104
|
+
const foreignKey = generateForeignKey(column, relatedTable);
|
|
105
|
+
column.relationshipType = type;
|
|
106
|
+
column.foreignKey = isOneSide ? foreignKey : primary;
|
|
107
|
+
column.fieldName = isOneSide ? primary : foreignKey;
|
|
108
|
+
return foreignKey;
|
|
109
|
+
}
|
|
110
|
+
function generateRelatedSchema(linkColumn, table, relatedTable, columnName) {
|
|
111
|
+
// generate column for other table
|
|
112
|
+
const relatedSchema = cloneDeep(linkColumn);
|
|
113
|
+
// swap them from the main link
|
|
114
|
+
if (linkColumn.foreignKey) {
|
|
115
|
+
relatedSchema.fieldName = linkColumn.foreignKey;
|
|
116
|
+
relatedSchema.foreignKey = linkColumn.fieldName;
|
|
117
|
+
}
|
|
118
|
+
// is many to many
|
|
119
|
+
else {
|
|
120
|
+
// don't need to copy through, already got it
|
|
121
|
+
relatedSchema.fieldName = linkColumn.throughFrom;
|
|
122
|
+
relatedSchema.throughTo = linkColumn.throughFrom;
|
|
123
|
+
relatedSchema.throughFrom = linkColumn.throughTo;
|
|
124
|
+
}
|
|
125
|
+
relatedSchema.relationshipType = otherRelationshipType(linkColumn.relationshipType);
|
|
126
|
+
relatedSchema.tableId = relatedTable._id;
|
|
127
|
+
relatedSchema.name = columnName;
|
|
128
|
+
table.schema[columnName] = relatedSchema;
|
|
129
|
+
}
|
|
130
|
+
function isRelationshipSetup(column) {
|
|
131
|
+
return column.foreignKey || column.through;
|
|
132
|
+
}
|
|
133
|
+
exports.save = function (ctx) {
|
|
134
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
+
const appId = ctx.appId;
|
|
136
|
+
const table = ctx.request.body;
|
|
137
|
+
// can't do this
|
|
138
|
+
delete table.dataImport;
|
|
139
|
+
const datasourceId = getDatasourceId(ctx.request.body);
|
|
140
|
+
let tableToSave = Object.assign({ type: "table", _id: buildExternalTableId(datasourceId, table.name) }, table);
|
|
141
|
+
let oldTable;
|
|
142
|
+
if (ctx.request.body && ctx.request.body._id) {
|
|
143
|
+
oldTable = yield getTable(appId, ctx.request.body._id);
|
|
144
|
+
}
|
|
145
|
+
const db = new CouchDB(appId);
|
|
146
|
+
const datasource = yield db.get(datasourceId);
|
|
147
|
+
const oldTables = cloneDeep(datasource.entities);
|
|
148
|
+
const tables = datasource.entities;
|
|
149
|
+
const extraTablesToUpdate = [];
|
|
150
|
+
// check if relations need setup
|
|
151
|
+
for (let schema of Object.values(tableToSave.schema)) {
|
|
152
|
+
if (schema.type !== FieldTypes.LINK || isRelationshipSetup(schema)) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const relatedTable = Object.values(tables).find(table => table._id === schema.tableId);
|
|
156
|
+
const relatedColumnName = schema.fieldName;
|
|
157
|
+
const relationType = schema.relationshipType;
|
|
158
|
+
if (relationType === RelationshipTypes.MANY_TO_MANY) {
|
|
159
|
+
const junctionTable = generateManyLinkSchema(datasource, schema, table, relatedTable);
|
|
160
|
+
if (tables[junctionTable.name]) {
|
|
161
|
+
throw "Junction table already exists, cannot create another relationship.";
|
|
162
|
+
}
|
|
163
|
+
tables[junctionTable.name] = junctionTable;
|
|
164
|
+
extraTablesToUpdate.push(junctionTable);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const fkTable = relationType === RelationshipTypes.ONE_TO_MANY ? table : relatedTable;
|
|
168
|
+
const foreignKey = generateLinkSchema(schema, table, relatedTable, relationType);
|
|
169
|
+
fkTable.schema[foreignKey] = foreignKeyStructure(foreignKey);
|
|
170
|
+
if (fkTable.constrained == null) {
|
|
171
|
+
fkTable.constrained = [];
|
|
172
|
+
}
|
|
173
|
+
if (fkTable.constrained.indexOf(foreignKey) === -1) {
|
|
174
|
+
fkTable.constrained.push(foreignKey);
|
|
175
|
+
}
|
|
176
|
+
// foreign key is in other table, need to save it to external
|
|
177
|
+
if (fkTable._id !== table._id) {
|
|
178
|
+
extraTablesToUpdate.push(fkTable);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
generateRelatedSchema(schema, relatedTable, table, relatedColumnName);
|
|
182
|
+
schema.main = true;
|
|
183
|
+
}
|
|
184
|
+
cleanupRelationships(tableToSave, tables, oldTable);
|
|
185
|
+
const operation = oldTable
|
|
186
|
+
? DataSourceOperation.UPDATE_TABLE
|
|
187
|
+
: DataSourceOperation.CREATE_TABLE;
|
|
188
|
+
yield makeTableRequest(datasource, operation, tableToSave, tables, oldTable);
|
|
189
|
+
// update any extra tables (like foreign keys in other tables)
|
|
190
|
+
for (let extraTable of extraTablesToUpdate) {
|
|
191
|
+
const oldExtraTable = oldTables[extraTable.name];
|
|
192
|
+
let op = oldExtraTable
|
|
193
|
+
? DataSourceOperation.UPDATE_TABLE
|
|
194
|
+
: DataSourceOperation.CREATE_TABLE;
|
|
195
|
+
yield makeTableRequest(datasource, op, extraTable, tables, oldExtraTable);
|
|
196
|
+
}
|
|
197
|
+
// make sure the constrained list, all still exist
|
|
198
|
+
if (Array.isArray(tableToSave.constrained)) {
|
|
199
|
+
tableToSave.constrained = tableToSave.constrained.filter(constraint => Object.keys(tableToSave.schema).includes(constraint));
|
|
200
|
+
}
|
|
201
|
+
// store it into couch now for budibase reference
|
|
202
|
+
datasource.entities[tableToSave.name] = tableToSave;
|
|
203
|
+
yield db.put(datasource);
|
|
204
|
+
return tableToSave;
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
exports.destroy = function (ctx) {
|
|
208
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
209
|
+
const appId = ctx.appId;
|
|
210
|
+
const tableToDelete = yield getTable(appId, ctx.params.tableId);
|
|
211
|
+
const datasourceId = getDatasourceId(tableToDelete);
|
|
212
|
+
const db = new CouchDB(appId);
|
|
213
|
+
const datasource = yield db.get(datasourceId);
|
|
214
|
+
const tables = datasource.entities;
|
|
215
|
+
const operation = DataSourceOperation.DELETE_TABLE;
|
|
216
|
+
yield makeTableRequest(datasource, operation, tableToDelete, tables);
|
|
217
|
+
cleanupRelationships(tableToDelete, tables);
|
|
218
|
+
delete datasource.entities[tableToDelete.name];
|
|
219
|
+
yield db.put(datasource);
|
|
220
|
+
return tableToDelete;
|
|
221
|
+
});
|
|
222
|
+
};
|
|
@@ -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,120 +53,24 @@ 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.` };
|
|
167
74
|
});
|
|
168
75
|
};
|
|
169
76
|
exports.validateCSVSchema = function (ctx) {
|