@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
|
@@ -26,6 +26,9 @@ const { clientLibraryPath, stringToReadStream } = require("../../utilities");
|
|
|
26
26
|
const { getAllLocks } = require("../../utilities/redis");
|
|
27
27
|
const { updateClientLibrary, backupClientLibrary, revertClientLibrary, } = require("../../utilities/fileSystem/clientLibrary");
|
|
28
28
|
const { getTenantId, isMultiTenant } = require("@budibase/auth/tenancy");
|
|
29
|
+
const { syncGlobalUsers } = require("./user");
|
|
30
|
+
const { app: appCache } = require("@budibase/auth/cache");
|
|
31
|
+
const { cleanupAutomations } = require("../../automations/utils");
|
|
29
32
|
const URL_REGEX_SLASH = /\/|\\/g;
|
|
30
33
|
// utility function, need to do away with this
|
|
31
34
|
function getLayouts(db) {
|
|
@@ -213,6 +216,7 @@ exports.create = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
213
216
|
if (!env.isTest()) {
|
|
214
217
|
yield createApp(appId);
|
|
215
218
|
}
|
|
219
|
+
yield appCache.invalidateAppMetadata(appId, newApplication);
|
|
216
220
|
ctx.status = 200;
|
|
217
221
|
ctx.body = newApplication;
|
|
218
222
|
});
|
|
@@ -267,8 +271,12 @@ exports.delete = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
267
271
|
if (!env.isTest() && !ctx.query.unpublish) {
|
|
268
272
|
yield deleteApp(ctx.params.appId);
|
|
269
273
|
}
|
|
274
|
+
if (ctx.query && ctx.query.unpublish) {
|
|
275
|
+
yield cleanupAutomations(ctx.params.appId);
|
|
276
|
+
}
|
|
270
277
|
// make sure the app/role doesn't stick around after the app has been deleted
|
|
271
278
|
yield removeAppFromUserRoles(ctx, ctx.params.appId);
|
|
279
|
+
yield appCache.invalidateAppMetadata(ctx.params.appId);
|
|
272
280
|
ctx.status = 200;
|
|
273
281
|
ctx.body = result;
|
|
274
282
|
});
|
|
@@ -277,6 +285,7 @@ exports.sync = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
277
285
|
if (!isDevAppID(appId)) {
|
|
278
286
|
ctx.throw(400, "This action cannot be performed for production apps");
|
|
279
287
|
}
|
|
288
|
+
// replicate prod to dev
|
|
280
289
|
const prodAppId = getDeployedAppID(appId);
|
|
281
290
|
try {
|
|
282
291
|
const prodDb = new CouchDB(prodAppId, { skip_setup: true });
|
|
@@ -307,6 +316,8 @@ exports.sync = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
307
316
|
catch (err) {
|
|
308
317
|
error = err;
|
|
309
318
|
}
|
|
319
|
+
// sync the users
|
|
320
|
+
yield syncGlobalUsers(appId);
|
|
310
321
|
if (error) {
|
|
311
322
|
ctx.throw(400, error);
|
|
312
323
|
}
|
|
@@ -327,7 +338,10 @@ const updateAppPackage = (ctx, appPackage, appId) => __awaiter(void 0, void 0, v
|
|
|
327
338
|
// the locked by property is attached by server but generated from
|
|
328
339
|
// Redis, shouldn't ever store it
|
|
329
340
|
delete newAppPackage.lockedBy;
|
|
330
|
-
|
|
341
|
+
const response = yield db.put(newAppPackage);
|
|
342
|
+
// remove any cached metadata, so that it will be updated
|
|
343
|
+
yield appCache.invalidateAppMetadata(appId);
|
|
344
|
+
return response;
|
|
331
345
|
});
|
|
332
346
|
const createEmptyAppPackage = (ctx, app) => __awaiter(void 0, void 0, void 0, function* () {
|
|
333
347
|
const db = new CouchDB(app.appId);
|
|
@@ -22,6 +22,8 @@ exports.fetchSelf = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
24
|
const user = yield getFullUser(ctx, userId);
|
|
25
|
+
// this shouldn't be returned by the app self
|
|
26
|
+
delete user.roles;
|
|
25
27
|
if (appId) {
|
|
26
28
|
const db = new CouchDB(appId);
|
|
27
29
|
// remove the full roles structure
|
|
@@ -40,9 +42,7 @@ exports.fetchSelf = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
40
42
|
}
|
|
41
43
|
// user has a role of some sort, return them
|
|
42
44
|
else if (err.status === 404) {
|
|
43
|
-
const metadata = {
|
|
44
|
-
_id: userId,
|
|
45
|
-
};
|
|
45
|
+
const metadata = Object.assign(Object.assign({}, user), { _id: userId });
|
|
46
46
|
const dbResp = yield db.put(metadata);
|
|
47
47
|
user._rev = dbResp.rev;
|
|
48
48
|
response = user;
|
|
@@ -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, InvalidColumns } = 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,17 +86,23 @@ 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) {
|
|
88
97
|
return __awaiter(this, void 0, void 0, function* () {
|
|
89
98
|
const db = new CouchDB(ctx.appId);
|
|
90
99
|
// Delete all queries for the datasource
|
|
91
|
-
const
|
|
92
|
-
yield db.bulkDocs(
|
|
100
|
+
const queries = yield db.allDocs(getQueryParams(ctx.params.datasourceId, null));
|
|
101
|
+
yield db.bulkDocs(queries.rows.map(row => ({
|
|
102
|
+
_id: row.id,
|
|
103
|
+
_rev: row.value.rev,
|
|
104
|
+
_deleted: true,
|
|
105
|
+
})));
|
|
93
106
|
// delete the datasource
|
|
94
107
|
yield db.remove(ctx.params.datasourceId, ctx.params.revId);
|
|
95
108
|
ctx.message = `Datasource deleted.`;
|
|
@@ -107,18 +120,56 @@ exports.query = function (ctx) {
|
|
|
107
120
|
return __awaiter(this, void 0, void 0, function* () {
|
|
108
121
|
const queryJson = ctx.request.body;
|
|
109
122
|
try {
|
|
110
|
-
ctx.body = yield
|
|
123
|
+
ctx.body = yield getDatasourceAndQuery(ctx.appId, queryJson);
|
|
111
124
|
}
|
|
112
125
|
catch (err) {
|
|
113
126
|
ctx.throw(400, err);
|
|
114
127
|
}
|
|
115
128
|
});
|
|
116
129
|
};
|
|
130
|
+
function getErrorTables(errors, errorType) {
|
|
131
|
+
return Object.entries(errors)
|
|
132
|
+
.filter(entry => entry[1] === errorType)
|
|
133
|
+
.map(([name]) => name);
|
|
134
|
+
}
|
|
135
|
+
function updateError(error, newError, tables) {
|
|
136
|
+
if (!error) {
|
|
137
|
+
error = "";
|
|
138
|
+
}
|
|
139
|
+
if (error.length > 0) {
|
|
140
|
+
error += "\n";
|
|
141
|
+
}
|
|
142
|
+
error += `${newError} ${tables.join(", ")}`;
|
|
143
|
+
return error;
|
|
144
|
+
}
|
|
117
145
|
const buildSchemaHelper = (datasource) => __awaiter(void 0, void 0, void 0, function* () {
|
|
118
146
|
const Connector = integrations[datasource.source];
|
|
119
147
|
// Connect to the DB and build the schema
|
|
120
148
|
const connector = new Connector(datasource.config);
|
|
121
149
|
yield connector.buildSchema(datasource._id, datasource.entities);
|
|
122
150
|
datasource.entities = connector.tables;
|
|
123
|
-
|
|
151
|
+
// make sure they all have a display name selected
|
|
152
|
+
for (let entity of Object.values(datasource.entities)) {
|
|
153
|
+
if (entity.primaryDisplay) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const notAutoColumn = Object.values(entity.schema).find(schema => !schema.autocolumn);
|
|
157
|
+
if (notAutoColumn) {
|
|
158
|
+
entity.primaryDisplay = notAutoColumn.name;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const errors = connector.schemaErrors;
|
|
162
|
+
let error = null;
|
|
163
|
+
if (errors && Object.keys(errors).length > 0) {
|
|
164
|
+
const noKey = getErrorTables(errors, BuildSchemaErrors.NO_KEY);
|
|
165
|
+
const invalidCol = getErrorTables(errors, BuildSchemaErrors.INVALID_COLUMN);
|
|
166
|
+
if (noKey.length) {
|
|
167
|
+
error = updateError(error, "No primary key constraint found for the following:", noKey);
|
|
168
|
+
}
|
|
169
|
+
if (invalidCol.length) {
|
|
170
|
+
const invalidCols = Object.values(InvalidColumns).join(", ");
|
|
171
|
+
error = updateError(error, `Cannot use columns ${invalidCols} found in following:`, invalidCol);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { tables: connector.tables, error };
|
|
124
175
|
});
|
|
@@ -13,6 +13,7 @@ const Deployment = require("./Deployment");
|
|
|
13
13
|
const { Replication, getDeployedAppID } = require("@budibase/auth/db");
|
|
14
14
|
const { DocumentTypes, getAutomationParams } = require("../../../db/utils");
|
|
15
15
|
const { disableAllCrons, enableCronTrigger, } = require("../../../automations/utils");
|
|
16
|
+
const { app: appCache } = require("@budibase/auth/cache");
|
|
16
17
|
// the max time we can wait for an invalidation to complete before considering it failed
|
|
17
18
|
const MAX_PENDING_TIME_MS = 30 * 60000;
|
|
18
19
|
const DeploymentStatus = {
|
|
@@ -95,6 +96,7 @@ function deployApp(deployment) {
|
|
|
95
96
|
appDoc.appId = productionAppId;
|
|
96
97
|
appDoc.instance._id = productionAppId;
|
|
97
98
|
yield db.put(appDoc);
|
|
99
|
+
yield appCache.invalidateAppMetadata(productionAppId);
|
|
98
100
|
console.log("New app doc written successfully.");
|
|
99
101
|
yield initDeployedApp(productionAppId);
|
|
100
102
|
console.log("Deployed app initialised, setting deployment to successful");
|
|
@@ -16,6 +16,7 @@ const { request } = require("../../utilities/workerRequests");
|
|
|
16
16
|
const { clearLock } = require("../../utilities/redis");
|
|
17
17
|
const { Replication } = require("@budibase/auth").db;
|
|
18
18
|
const { DocumentTypes } = require("../../db/utils");
|
|
19
|
+
const { app: appCache } = require("@budibase/auth/cache");
|
|
19
20
|
function redirect(ctx, method, path = "global") {
|
|
20
21
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21
22
|
const { devPath } = ctx.params;
|
|
@@ -25,7 +26,8 @@ function redirect(ctx, method, path = "global") {
|
|
|
25
26
|
body: ctx.request.body,
|
|
26
27
|
}, true));
|
|
27
28
|
if (response.status !== 200) {
|
|
28
|
-
|
|
29
|
+
const err = yield response.text();
|
|
30
|
+
ctx.throw(400, err);
|
|
29
31
|
}
|
|
30
32
|
const cookie = response.headers.get("set-cookie");
|
|
31
33
|
if (cookie) {
|
|
@@ -102,6 +104,7 @@ exports.revert = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
102
104
|
appDoc.appId = appId;
|
|
103
105
|
appDoc.instance._id = appId;
|
|
104
106
|
yield db.put(appDoc);
|
|
107
|
+
yield appCache.invalidateAppMetadata(appId);
|
|
105
108
|
ctx.body = {
|
|
106
109
|
message: "Reverted changes successfully.",
|
|
107
110
|
};
|
|
@@ -11,10 +11,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
const { processString } = require("@budibase/string-templates");
|
|
12
12
|
const CouchDB = require("../../db");
|
|
13
13
|
const { generateQueryID, getQueryParams } = require("../../db/utils");
|
|
14
|
-
const { integrations } = require("../../integrations");
|
|
15
14
|
const { BaseQueryVerbs } = require("../../constants");
|
|
16
15
|
const env = require("../../environment");
|
|
17
|
-
const
|
|
16
|
+
const { Thread, ThreadType } = require("../../threads");
|
|
17
|
+
const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 });
|
|
18
18
|
// simple function to append "readable" to all read queries
|
|
19
19
|
function enrichQueries(input) {
|
|
20
20
|
const wasArray = Array.isArray(input);
|
|
@@ -26,38 +26,6 @@ function enrichQueries(input) {
|
|
|
26
26
|
}
|
|
27
27
|
return wasArray ? queries : queries[0];
|
|
28
28
|
}
|
|
29
|
-
function formatResponse(resp) {
|
|
30
|
-
if (typeof resp === "string") {
|
|
31
|
-
try {
|
|
32
|
-
resp = JSON.parse(resp);
|
|
33
|
-
}
|
|
34
|
-
catch (err) {
|
|
35
|
-
resp = { response: resp };
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return resp;
|
|
39
|
-
}
|
|
40
|
-
function runAndTransform(integration, queryVerb, enrichedQuery, transformer) {
|
|
41
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
-
let rows = formatResponse(yield integration[queryVerb](enrichedQuery));
|
|
43
|
-
// transform as required
|
|
44
|
-
if (transformer) {
|
|
45
|
-
const runner = new ScriptRunner(transformer, { data: rows });
|
|
46
|
-
rows = runner.execute();
|
|
47
|
-
}
|
|
48
|
-
// needs to an array for next step
|
|
49
|
-
if (!Array.isArray(rows)) {
|
|
50
|
-
rows = [rows];
|
|
51
|
-
}
|
|
52
|
-
// map into JSON if just raw primitive here
|
|
53
|
-
if (rows.find(row => typeof row !== "object")) {
|
|
54
|
-
rows = rows.map(value => ({ value }));
|
|
55
|
-
}
|
|
56
|
-
// get all the potential fields in the schema
|
|
57
|
-
let keys = rows.flatMap(Object.keys);
|
|
58
|
-
return { rows, keys };
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
29
|
exports.fetch = function (ctx) {
|
|
62
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
63
31
|
const db = new CouchDB(ctx.appId);
|
|
@@ -94,7 +62,9 @@ function enrichQueryFields(fields, parameters = {}) {
|
|
|
94
62
|
}
|
|
95
63
|
else if (typeof fields[key] === "string") {
|
|
96
64
|
// enrich string value as normal
|
|
97
|
-
enrichedQuery[key] = yield processString(fields[key], parameters
|
|
65
|
+
enrichedQuery[key] = yield processString(fields[key], parameters, {
|
|
66
|
+
noHelpers: true,
|
|
67
|
+
});
|
|
98
68
|
}
|
|
99
69
|
else {
|
|
100
70
|
enrichedQuery[key] = fields[key];
|
|
@@ -133,21 +103,22 @@ exports.preview = function (ctx) {
|
|
|
133
103
|
return __awaiter(this, void 0, void 0, function* () {
|
|
134
104
|
const db = new CouchDB(ctx.appId);
|
|
135
105
|
const datasource = yield db.get(ctx.request.body.datasourceId);
|
|
136
|
-
const Integration = integrations[datasource.source];
|
|
137
|
-
if (!Integration) {
|
|
138
|
-
ctx.throw(400, "Integration type does not exist.");
|
|
139
|
-
}
|
|
140
106
|
const { fields, parameters, queryVerb, transformer } = ctx.request.body;
|
|
141
107
|
const enrichedQuery = yield enrichQueryFields(fields, parameters);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
108
|
+
try {
|
|
109
|
+
const { rows, keys } = yield Runner.run({
|
|
110
|
+
datasource,
|
|
111
|
+
queryVerb,
|
|
112
|
+
query: enrichedQuery,
|
|
113
|
+
transformer,
|
|
114
|
+
});
|
|
115
|
+
ctx.body = {
|
|
116
|
+
rows,
|
|
117
|
+
schemaFields: [...new Set(keys)],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
ctx.throw(400, err);
|
|
151
122
|
}
|
|
152
123
|
});
|
|
153
124
|
};
|
|
@@ -156,18 +127,19 @@ exports.execute = function (ctx) {
|
|
|
156
127
|
const db = new CouchDB(ctx.appId);
|
|
157
128
|
const query = yield db.get(ctx.params.queryId);
|
|
158
129
|
const datasource = yield db.get(query.datasourceId);
|
|
159
|
-
const Integration = integrations[datasource.source];
|
|
160
|
-
if (!Integration) {
|
|
161
|
-
ctx.throw(400, "Integration type does not exist.");
|
|
162
|
-
}
|
|
163
130
|
const enrichedQuery = yield enrichQueryFields(query.fields, ctx.request.body.parameters);
|
|
164
|
-
const integration = new Integration(datasource.config);
|
|
165
131
|
// call the relevant CRUD method on the integration class
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
132
|
+
try {
|
|
133
|
+
const { rows } = yield Runner.run({
|
|
134
|
+
datasource,
|
|
135
|
+
queryVerb: query.queryVerb,
|
|
136
|
+
query: enrichedQuery,
|
|
137
|
+
transformer: query.transformer,
|
|
138
|
+
});
|
|
139
|
+
ctx.body = rows;
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
ctx.throw(400, err);
|
|
171
143
|
}
|
|
172
144
|
});
|
|
173
145
|
};
|
|
@@ -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
|
|
@@ -151,8 +152,23 @@ var External;
|
|
|
151
152
|
thisRow._rev = "rev";
|
|
152
153
|
return thisRow;
|
|
153
154
|
}
|
|
154
|
-
function
|
|
155
|
-
|
|
155
|
+
function fixArrayTypes(row, table) {
|
|
156
|
+
for (let [fieldName, schema] of Object.entries(table.schema)) {
|
|
157
|
+
if (schema.type === FieldTypes.ARRAY &&
|
|
158
|
+
typeof row[fieldName] === "string") {
|
|
159
|
+
try {
|
|
160
|
+
row[fieldName] = JSON.parse(row[fieldName]);
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
// couldn't convert back to array, ignore
|
|
164
|
+
delete row[fieldName];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return row;
|
|
169
|
+
}
|
|
170
|
+
function isOneSide(field) {
|
|
171
|
+
return (field.relationshipType && field.relationshipType.split("-")[0] === "one");
|
|
156
172
|
}
|
|
157
173
|
class ExternalRequest {
|
|
158
174
|
constructor(appId, operation, tableId, datasource) {
|
|
@@ -182,7 +198,10 @@ var External;
|
|
|
182
198
|
let newRow = {}, manyRelationships = [];
|
|
183
199
|
for (let [key, field] of Object.entries(table.schema)) {
|
|
184
200
|
// if set already, or not set just skip it
|
|
185
|
-
if (
|
|
201
|
+
if (row[key] == null ||
|
|
202
|
+
newRow[key] ||
|
|
203
|
+
field.autocolumn ||
|
|
204
|
+
field.type === FieldTypes.FORMULA) {
|
|
186
205
|
continue;
|
|
187
206
|
}
|
|
188
207
|
// if its an empty string then it means return the column to null (if possible)
|
|
@@ -207,24 +226,35 @@ var External;
|
|
|
207
226
|
const linkTable = this.tables[linkTableName];
|
|
208
227
|
// @ts-ignore
|
|
209
228
|
const linkTablePrimary = linkTable.primary[0];
|
|
210
|
-
|
|
229
|
+
// one to many
|
|
230
|
+
if (isOneSide(field)) {
|
|
211
231
|
newRow[field.foreignKey || linkTablePrimary] = utils_1.breakRowIdField(row[key][0])[0];
|
|
212
232
|
}
|
|
213
|
-
|
|
233
|
+
// many to many
|
|
234
|
+
else if (field.through) {
|
|
214
235
|
// 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;
|
|
236
|
+
const otherKey = field.throughFrom || linkTablePrimary;
|
|
237
|
+
const thisKey = field.throughTo || tablePrimary;
|
|
223
238
|
row[key].map((relationship) => {
|
|
224
|
-
// we don't really support composite keys for relationships, this is why [0] is used
|
|
225
239
|
manyRelationships.push({
|
|
226
240
|
tableId: field.through || field.tableId,
|
|
227
|
-
isUpdate,
|
|
241
|
+
isUpdate: false,
|
|
242
|
+
key: otherKey,
|
|
243
|
+
[otherKey]: utils_1.breakRowIdField(relationship)[0],
|
|
244
|
+
// leave the ID for enrichment later
|
|
245
|
+
[thisKey]: `{{ literal ${tablePrimary} }}`,
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
// many to one
|
|
250
|
+
else {
|
|
251
|
+
const thisKey = "id";
|
|
252
|
+
// @ts-ignore
|
|
253
|
+
const otherKey = field.fieldName;
|
|
254
|
+
row[key].map((relationship) => {
|
|
255
|
+
manyRelationships.push({
|
|
256
|
+
tableId: field.tableId,
|
|
257
|
+
isUpdate: true,
|
|
228
258
|
key: otherKey,
|
|
229
259
|
[thisKey]: utils_1.breakRowIdField(relationship)[0],
|
|
230
260
|
// leave the ID for enrichment later
|
|
@@ -278,7 +308,7 @@ var External;
|
|
|
278
308
|
return rows;
|
|
279
309
|
}
|
|
280
310
|
outputProcessing(rows = [], table, relationships) {
|
|
281
|
-
if (rows[0].read === true) {
|
|
311
|
+
if (!rows || rows.length === 0 || rows[0].read === true) {
|
|
282
312
|
return [];
|
|
283
313
|
}
|
|
284
314
|
let finalRows = {};
|
|
@@ -290,12 +320,15 @@ var External;
|
|
|
290
320
|
finalRows = this.updateRelationshipColumns(row, finalRows, relationships);
|
|
291
321
|
continue;
|
|
292
322
|
}
|
|
293
|
-
const thisRow = basicProcessing(row, table);
|
|
323
|
+
const thisRow = fixArrayTypes(basicProcessing(row, table), table);
|
|
324
|
+
if (thisRow._id == null) {
|
|
325
|
+
throw "Unable to generate row ID for SQL rows";
|
|
326
|
+
}
|
|
294
327
|
finalRows[thisRow._id] = thisRow;
|
|
295
328
|
// do this at end once its been added to the final rows
|
|
296
329
|
finalRows = this.updateRelationshipColumns(row, finalRows, relationships);
|
|
297
330
|
}
|
|
298
|
-
return Object.values(finalRows);
|
|
331
|
+
return processFormulas(table, Object.values(finalRows));
|
|
299
332
|
}
|
|
300
333
|
/**
|
|
301
334
|
* Gets the list of relationship JSON structures based on the columns in the table,
|
|
@@ -329,8 +362,8 @@ var External;
|
|
|
329
362
|
const { tableName: throughTableName } = breakExternalTableId(field.through);
|
|
330
363
|
definition.through = throughTableName;
|
|
331
364
|
// don't support composite keys for relationships
|
|
332
|
-
definition.from = field.
|
|
333
|
-
definition.to = field.
|
|
365
|
+
definition.from = field.throughTo || table.primary[0];
|
|
366
|
+
definition.to = field.throughFrom || linkTable.primary[0];
|
|
334
367
|
definition.fromPrimary = table.primary[0];
|
|
335
368
|
definition.toPrimary = linkTable.primary[0];
|
|
336
369
|
}
|
|
@@ -352,24 +385,34 @@ var External;
|
|
|
352
385
|
// make a new request to get the row with all its relationships
|
|
353
386
|
// we need this to work out if any relationships need removed
|
|
354
387
|
for (let field of Object.values(table.schema)) {
|
|
355
|
-
if (field.type !== FieldTypes.LINK ||
|
|
388
|
+
if (field.type !== FieldTypes.LINK ||
|
|
389
|
+
!field.fieldName ||
|
|
390
|
+
isOneSide(field)) {
|
|
356
391
|
continue;
|
|
357
392
|
}
|
|
358
393
|
const isMany = field.relationshipType === RelationshipTypes.MANY_TO_MANY;
|
|
359
394
|
const tableId = isMany ? field.through : field.tableId;
|
|
360
|
-
const
|
|
395
|
+
const { tableName: relatedTableName } = breakExternalTableId(tableId);
|
|
396
|
+
// @ts-ignore
|
|
397
|
+
const linkPrimaryKey = this.tables[relatedTableName].primary[0];
|
|
398
|
+
const manyKey = field.throughTo || primaryKey;
|
|
399
|
+
const lookupField = isMany ? primaryKey : field.foreignKey;
|
|
361
400
|
const fieldName = isMany ? manyKey : field.fieldName;
|
|
362
|
-
|
|
401
|
+
if (!lookupField || !row[lookupField]) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
const response = yield getDatasourceAndQuery(this.appId, {
|
|
363
405
|
endpoint: getEndpoint(tableId, DataSourceOperation.READ),
|
|
364
406
|
filters: {
|
|
365
407
|
equal: {
|
|
366
|
-
[fieldName]: row[
|
|
408
|
+
[fieldName]: row[lookupField],
|
|
367
409
|
},
|
|
368
410
|
},
|
|
369
411
|
});
|
|
370
412
|
// this is the response from knex if no rows found
|
|
371
413
|
const rows = !response[0].read ? response : [];
|
|
372
|
-
|
|
414
|
+
const storeTo = isMany ? field.throughFrom || linkPrimaryKey : manyKey;
|
|
415
|
+
related[storeTo] = { rows, isMany, tableId };
|
|
373
416
|
}
|
|
374
417
|
return related;
|
|
375
418
|
});
|
|
@@ -403,7 +446,7 @@ var External;
|
|
|
403
446
|
? DataSourceOperation.UPDATE
|
|
404
447
|
: DataSourceOperation.CREATE;
|
|
405
448
|
if (!found) {
|
|
406
|
-
promises.push(
|
|
449
|
+
promises.push(getDatasourceAndQuery(appId, {
|
|
407
450
|
endpoint: getEndpoint(tableId, operation),
|
|
408
451
|
// if we're doing many relationships then we're writing, only one response
|
|
409
452
|
body,
|
|
@@ -430,7 +473,7 @@ var External;
|
|
|
430
473
|
? DataSourceOperation.DELETE
|
|
431
474
|
: DataSourceOperation.UPDATE;
|
|
432
475
|
const body = isMany ? null : { [colName]: null };
|
|
433
|
-
promises.push(
|
|
476
|
+
promises.push(getDatasourceAndQuery(this.appId, {
|
|
434
477
|
endpoint: getEndpoint(tableId, op),
|
|
435
478
|
body,
|
|
436
479
|
filters,
|
|
@@ -449,13 +492,14 @@ var External;
|
|
|
449
492
|
* is more performant and has the added benefit of protecting against this scenario.
|
|
450
493
|
*/
|
|
451
494
|
buildFields(table, includeRelations = datasource_1.IncludeRelationships.INCLUDE) {
|
|
452
|
-
function
|
|
495
|
+
function extractRealFields(table, existing = []) {
|
|
453
496
|
return Object.entries(table.schema)
|
|
454
497
|
.filter(column => column[1].type !== FieldTypes.LINK &&
|
|
498
|
+
column[1].type !== FieldTypes.FORMULA &&
|
|
455
499
|
!existing.find((field) => field === column[0]))
|
|
456
500
|
.map(column => `${table.name}.${column[0]}`);
|
|
457
501
|
}
|
|
458
|
-
let fields =
|
|
502
|
+
let fields = extractRealFields(table);
|
|
459
503
|
for (let field of Object.values(table.schema)) {
|
|
460
504
|
if (field.type !== FieldTypes.LINK || !includeRelations) {
|
|
461
505
|
continue;
|
|
@@ -463,7 +507,7 @@ var External;
|
|
|
463
507
|
const { tableName: linkTableName } = breakExternalTableId(field.tableId);
|
|
464
508
|
const linkTable = this.tables[linkTableName];
|
|
465
509
|
if (linkTable) {
|
|
466
|
-
const linkedFields =
|
|
510
|
+
const linkedFields = extractRealFields(linkTable, fields);
|
|
467
511
|
fields = fields.concat(linkedFields);
|
|
468
512
|
}
|
|
469
513
|
}
|
|
@@ -487,7 +531,7 @@ var External;
|
|
|
487
531
|
throw `Unable to process query, table "${tableName}" not defined.`;
|
|
488
532
|
}
|
|
489
533
|
// look for specific components of config which may not be considered acceptable
|
|
490
|
-
let { id, row, filters, sort, paginate } = cleanupConfig(config, table);
|
|
534
|
+
let { id, row, filters, sort, paginate, rows } = cleanupConfig(config, table);
|
|
491
535
|
filters = buildFilters(id, filters || {}, table);
|
|
492
536
|
const relationships = this.buildRelationships(table);
|
|
493
537
|
// clean up row on ingress using schema
|
|
@@ -511,7 +555,7 @@ var External;
|
|
|
511
555
|
sort,
|
|
512
556
|
paginate,
|
|
513
557
|
relationships,
|
|
514
|
-
body: row,
|
|
558
|
+
body: row || rows,
|
|
515
559
|
// pass an id filter into extra, purely for mysql/returning
|
|
516
560
|
extra: {
|
|
517
561
|
idFilter: buildFilters(id || generateIdForRow(row, table), {}, table),
|
|
@@ -521,7 +565,7 @@ var External;
|
|
|
521
565
|
},
|
|
522
566
|
};
|
|
523
567
|
// can't really use response right now
|
|
524
|
-
const response = yield
|
|
568
|
+
const response = yield getDatasourceAndQuery(appId, json);
|
|
525
569
|
// handle many to many relationships now if we know the ID (could be auto increment)
|
|
526
570
|
if (operation !== DataSourceOperation.READ &&
|
|
527
571
|
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* () {
|