@budibase/server 1.0.47 → 1.0.49-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.937b2767.js → index.82e12602.js} +234 -231
- package/builder/assets/index.83c0944f.css +1 -0
- package/builder/assets/{vendor.f9faf6ab.js → vendor.d526bfe8.js} +12 -12
- package/builder/index.html +3 -3
- package/coverage/clover.xml +2334 -2013
- package/coverage/coverage-final.json +100 -95
- 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 +210 -126
- package/coverage/lcov-report/api/controllers/auth.js.html +18 -6
- package/coverage/lcov-report/api/controllers/automation.js.html +21 -21
- 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 +72 -36
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +53 -53
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +6 -6
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/migrations.js.html +119 -0
- package/coverage/lcov-report/api/controllers/permission.js.html +15 -15
- package/coverage/lcov-report/api/controllers/query/index.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.js.html +19 -19
- package/coverage/lcov-report/api/controllers/query/validation.js.html +6 -6
- package/coverage/lcov-report/api/controllers/role.js.html +9 -9
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +16 -16
- package/coverage/lcov-report/api/controllers/row/index.html +48 -33
- package/coverage/lcov-report/api/controllers/row/index.js.html +26 -26
- package/coverage/lcov-report/api/controllers/row/internal.js.html +95 -158
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +41 -17
- package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +551 -0
- package/coverage/lcov-report/api/controllers/row/utils.js.html +39 -57
- package/coverage/lcov-report/api/controllers/screen.js.html +7 -7
- package/coverage/lcov-report/api/controllers/script.js.html +4 -4
- package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +629 -0
- package/coverage/lcov-report/api/controllers/table/external.js.html +12 -12
- package/coverage/lcov-report/api/controllers/table/index.html +49 -34
- package/coverage/lcov-report/api/controllers/table/index.js.html +53 -77
- package/coverage/lcov-report/api/controllers/table/internal.js.html +59 -35
- package/coverage/lcov-report/api/controllers/table/utils.js.html +283 -76
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +30 -24
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +4 -4
- package/coverage/lcov-report/api/controllers/view/index.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.js.html +14 -14
- package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +7 -7
- package/coverage/lcov-report/api/controllers/webhook.js.html +15 -15
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +8 -8
- 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/index.html +18 -18
- package/coverage/lcov-report/api/routes/index.js.html +3 -3
- 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/{hosting.js.html → migrations.js.html} +17 -14
- 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 +17 -2
- 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 +24 -24
- package/coverage/lcov-report/automations/automationUtils.js.html +5 -5
- package/coverage/lcov-report/automations/bullboard.js.html +16 -16
- 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 +6 -6
- package/coverage/lcov-report/automations/steps/createRow.js.html +13 -19
- package/coverage/lcov-report/automations/steps/delay.js.html +4 -4
- package/coverage/lcov-report/automations/steps/deleteRow.js.html +11 -20
- package/coverage/lcov-report/automations/steps/discord.js.html +7 -7
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +6 -6
- package/coverage/lcov-report/automations/steps/executeScript.js.html +6 -6
- package/coverage/lcov-report/automations/steps/filter.js.html +7 -7
- package/coverage/lcov-report/automations/steps/index.html +13 -13
- package/coverage/lcov-report/automations/steps/integromat.js.html +5 -5
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +8 -8
- package/coverage/lcov-report/automations/steps/queryRows.js.html +10 -10
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +5 -5
- package/coverage/lcov-report/automations/steps/serverLog.js.html +3 -3
- package/coverage/lcov-report/automations/steps/slack.js.html +5 -5
- package/coverage/lcov-report/automations/steps/updateRow.js.html +6 -6
- package/coverage/lcov-report/automations/steps/utils.js.html +3 -3
- package/coverage/lcov-report/automations/steps/zapier.js.html +5 -5
- 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 +18 -18
- package/coverage/lcov-report/automations/utils.js.html +32 -32
- package/coverage/lcov-report/constants/index.html +11 -11
- package/coverage/lcov-report/constants/index.js.html +68 -32
- package/coverage/lcov-report/constants/layouts.js.html +5 -5
- package/coverage/lcov-report/constants/screens.js.html +4 -4
- package/coverage/lcov-report/db/client.js.html +18 -18
- package/coverage/lcov-report/db/inMemoryView.js.html +7 -7
- package/coverage/lcov-report/db/index.html +15 -15
- package/coverage/lcov-report/db/index.js.html +3 -3
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +18 -18
- package/coverage/lcov-report/db/linkedRows/index.html +10 -10
- package/coverage/lcov-report/db/linkedRows/index.js.html +38 -41
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +15 -15
- package/coverage/lcov-report/db/newid.js.html +4 -4
- package/coverage/lcov-report/db/utils.js.html +86 -86
- 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 +5 -5
- package/coverage/lcov-report/events/utils.js.html +3 -3
- package/coverage/lcov-report/index.html +117 -102
- 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 +166 -64
- package/coverage/lcov-report/middleware/builder.js.html +8 -8
- package/coverage/lcov-report/middleware/currentapp.js.html +29 -29
- package/coverage/lcov-report/middleware/index.html +30 -30
- package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
- 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 +270 -42
- package/coverage/lcov-report/middleware/utils.js.html +2 -2
- package/coverage/lcov-report/threads/automation.js.html +1 -1
- package/coverage/lcov-report/threads/index.html +15 -15
- package/coverage/lcov-report/threads/index.js.html +10 -10
- package/coverage/lcov-report/threads/query.js.html +23 -8
- package/coverage/lcov-report/threads/utils.js.html +14 -14
- package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
- package/coverage/lcov-report/utilities/budibaseDir.js.html +7 -7
- package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
- package/coverage/lcov-report/utilities/csvParser.js.html +6 -6
- package/coverage/lcov-report/utilities/global.js.html +26 -26
- package/coverage/lcov-report/utilities/index.html +19 -19
- package/coverage/lcov-report/utilities/index.js.html +25 -25
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +8 -8
- 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 +27 -27
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +115 -79
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +75 -27
- package/coverage/lcov-report/utilities/scriptRunner.js.html +5 -5
- package/coverage/lcov-report/utilities/security.js.html +8 -8
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/index.html +141 -0
- package/coverage/lcov-report/utilities/usageQuota/index.js.html +356 -0
- package/coverage/lcov-report/utilities/usageQuota/rows.js.html +302 -0
- package/coverage/lcov-report/{api/controllers/hosting.js.html → utilities/usageQuota/usageQuoteReset.js.html} +36 -48
- package/coverage/lcov-report/utilities/users.js.html +5 -5
- package/coverage/lcov-report/utilities/workerRequests.js.html +39 -108
- package/coverage/lcov.info +3665 -3040
- package/dist/api/controllers/application.js +61 -34
- package/dist/api/controllers/auth.js +4 -0
- package/dist/api/controllers/datasource.js +11 -0
- package/dist/api/controllers/migrations.js +21 -0
- package/dist/api/controllers/row/ExternalRequest.js +2 -1
- package/dist/api/controllers/row/internal.js +30 -53
- package/dist/api/controllers/row/internalSearch.js +12 -4
- package/dist/api/controllers/row/staticFormula.js +147 -0
- package/dist/api/controllers/row/utils.js +6 -8
- package/dist/api/controllers/static/index.js +59 -10
- package/dist/api/controllers/table/bulkFormula.js +160 -0
- package/dist/api/controllers/table/index.js +12 -9
- package/dist/api/controllers/table/internal.js +9 -0
- package/dist/api/controllers/table/utils.js +56 -14
- package/dist/api/controllers/user.js +2 -0
- package/dist/api/routes/index.js +2 -2
- package/dist/api/routes/migrations.js +9 -0
- package/dist/api/routes/static.js +2 -1
- package/dist/app.js +35 -5
- package/dist/automations/steps/createRow.js +2 -4
- package/dist/automations/steps/deleteRow.js +1 -4
- package/dist/constants/index.js +12 -5
- package/dist/db/linkedRows/index.js +4 -5
- package/dist/definitions/datasource.js +1 -0
- package/dist/environment.js +2 -0
- package/dist/integrations/base/sql.js +13 -6
- package/dist/integrations/googlesheets.js +340 -0
- package/dist/integrations/index.js +3 -0
- package/dist/integrations/utils.js +57 -8
- package/dist/middleware/authorized.js +55 -30
- package/dist/middleware/usageQuota.js +80 -13
- package/dist/migrations/functions/appUrls.js +37 -0
- package/dist/migrations/functions/quotas1.js +50 -0
- package/dist/migrations/functions/usageQuotas/index.js +20 -0
- package/dist/migrations/functions/usageQuotas/syncApps.js +32 -0
- package/dist/migrations/functions/usageQuotas/syncRows.js +35 -0
- package/dist/migrations/functions/userEmailViewCasing.js +24 -0
- package/dist/migrations/index.js +62 -0
- package/dist/package.json +8 -5
- package/dist/tests/utilities/TestConfiguration.js +13 -6
- package/dist/threads/query.js +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/rowProcessor/index.js +18 -11
- package/dist/utilities/rowProcessor/utils.js +14 -4
- package/dist/utilities/{usageQuota.js → usageQuota/index.js} +44 -31
- package/dist/utilities/usageQuota/rows.js +77 -0
- package/dist/utilities/usageQuota/usageQuoteReset.js +16 -0
- package/dist/utilities/workerRequests.js +0 -20
- package/nodemon.json +1 -1
- package/package.json +9 -6
- package/src/api/controllers/application.js +52 -24
- package/src/api/controllers/auth.js +4 -0
- package/src/api/controllers/datasource.js +12 -0
- package/src/api/controllers/migrations.js +13 -0
- package/src/api/controllers/row/ExternalRequest.ts +1 -1
- package/src/api/controllers/row/internal.js +29 -50
- package/src/api/controllers/row/internalSearch.js +12 -4
- package/src/api/controllers/row/staticFormula.js +157 -0
- package/src/api/controllers/row/utils.js +6 -12
- package/src/api/controllers/static/index.js +63 -10
- package/src/api/controllers/table/bulkFormula.js +183 -0
- package/src/api/controllers/table/index.js +16 -24
- package/src/api/controllers/table/internal.js +9 -1
- package/src/api/controllers/table/utils.js +80 -11
- package/src/api/controllers/user.js +2 -0
- package/src/api/routes/index.js +2 -2
- package/src/api/routes/migrations.js +14 -0
- package/src/api/routes/static.js +5 -0
- package/src/api/routes/tests/application.spec.js +2 -2
- package/src/api/routes/tests/auth.spec.js +1 -2
- package/src/api/routes/tests/static.spec.js +98 -0
- package/src/app.ts +18 -5
- package/src/automations/steps/createRow.js +2 -4
- package/src/automations/steps/deleteRow.js +1 -4
- package/src/constants/index.js +17 -5
- package/src/db/linkedRows/index.js +4 -5
- package/src/definitions/common.ts +3 -0
- package/src/definitions/datasource.ts +3 -0
- package/src/environment.js +2 -0
- package/src/integrations/base/sql.ts +14 -7
- package/src/integrations/googlesheets.ts +353 -0
- package/src/integrations/index.ts +3 -0
- package/src/integrations/tests/sql.spec.js +16 -0
- package/src/integrations/utils.ts +71 -10
- package/src/middleware/authorized.js +64 -30
- package/src/middleware/tests/authorized.spec.js +6 -4
- package/src/middleware/tests/usageQuota.spec.js +18 -24
- package/src/middleware/usageQuota.js +91 -15
- package/src/migrations/functions/appUrls.ts +25 -0
- package/src/migrations/functions/quotas1.ts +20 -0
- package/src/migrations/functions/tests/appUrls.spec.js +29 -0
- package/src/migrations/functions/tests/quotas1.spec.js +27 -0
- package/src/migrations/functions/tests/userEmailViewCasing.spec.js +25 -0
- package/src/migrations/functions/usageQuotas/index.ts +8 -0
- package/src/migrations/functions/usageQuotas/syncApps.ts +18 -0
- package/src/migrations/functions/usageQuotas/syncRows.ts +21 -0
- package/src/migrations/functions/usageQuotas/tests/syncApps.spec.js +37 -0
- package/src/migrations/functions/usageQuotas/tests/syncRows.spec.js +43 -0
- package/src/migrations/functions/userEmailViewCasing.ts +13 -0
- package/src/migrations/index.ts +56 -0
- package/src/tests/utilities/TestConfiguration.js +14 -6
- package/src/threads/query.js +5 -0
- package/src/utilities/rowProcessor/index.js +24 -12
- package/src/utilities/rowProcessor/utils.js +23 -7
- package/src/utilities/tests/usageQuota/usageQuota.spec.js +72 -0
- package/src/utilities/usageQuota/index.js +92 -0
- package/src/utilities/usageQuota/rows.js +74 -0
- package/src/utilities/usageQuota/usageQuoteReset.js +18 -0
- package/src/utilities/workerRequests.js +0 -23
- package/builder/assets/index.39e01193.css +0 -1
- package/dist/api/controllers/hosting.js +0 -30
- package/dist/api/routes/hosting.js +0 -11
- package/src/api/controllers/hosting.js +0 -22
- package/src/api/routes/hosting.js +0 -13
- package/src/api/routes/tests/hosting.spec.js +0 -36
- package/src/utilities/usageQuota.js +0 -73
|
@@ -72,16 +72,22 @@ class InternalBuilder {
|
|
|
72
72
|
|
|
73
73
|
// right now we only do filters on the specific table being queried
|
|
74
74
|
addFilters(
|
|
75
|
-
tableName: string,
|
|
76
75
|
query: KnexQuery,
|
|
77
|
-
filters: SearchFilters | undefined
|
|
76
|
+
filters: SearchFilters | undefined,
|
|
77
|
+
opts: { relationship?: boolean; tableName?: string }
|
|
78
78
|
): KnexQuery {
|
|
79
79
|
function iterate(
|
|
80
80
|
structure: { [key: string]: any },
|
|
81
81
|
fn: (key: string, value: any) => void
|
|
82
82
|
) {
|
|
83
83
|
for (let [key, value] of Object.entries(structure)) {
|
|
84
|
-
|
|
84
|
+
const isRelationshipField = key.includes(".")
|
|
85
|
+
if (!opts.relationship && !isRelationshipField) {
|
|
86
|
+
fn(`${opts.tableName}.${key}`, value)
|
|
87
|
+
}
|
|
88
|
+
if (opts.relationship && isRelationshipField) {
|
|
89
|
+
fn(key, value)
|
|
90
|
+
}
|
|
85
91
|
}
|
|
86
92
|
}
|
|
87
93
|
if (!filters) {
|
|
@@ -272,7 +278,7 @@ class InternalBuilder {
|
|
|
272
278
|
if (foundOffset) {
|
|
273
279
|
query = query.offset(foundOffset)
|
|
274
280
|
}
|
|
275
|
-
query = this.addFilters(
|
|
281
|
+
query = this.addFilters(query, filters, { tableName })
|
|
276
282
|
// add sorting to pre-query
|
|
277
283
|
query = this.addSorting(query, json)
|
|
278
284
|
// @ts-ignore
|
|
@@ -285,20 +291,21 @@ class InternalBuilder {
|
|
|
285
291
|
preQuery = this.addSorting(preQuery, json)
|
|
286
292
|
}
|
|
287
293
|
// handle joins
|
|
288
|
-
|
|
294
|
+
query = this.addRelationships(
|
|
289
295
|
knex,
|
|
290
296
|
preQuery,
|
|
291
297
|
selectStatement,
|
|
292
298
|
tableName,
|
|
293
299
|
relationships
|
|
294
300
|
)
|
|
301
|
+
return this.addFilters(query, filters, { relationship: true })
|
|
295
302
|
}
|
|
296
303
|
|
|
297
304
|
update(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
|
|
298
305
|
const { endpoint, body, filters } = json
|
|
299
306
|
let query: KnexQuery = knex(endpoint.entityId)
|
|
300
307
|
const parsedBody = parseBody(body)
|
|
301
|
-
query = this.addFilters(endpoint.entityId
|
|
308
|
+
query = this.addFilters(query, filters, { tableName: endpoint.entityId })
|
|
302
309
|
// mysql can't use returning
|
|
303
310
|
if (opts.disableReturning) {
|
|
304
311
|
return query.update(parsedBody)
|
|
@@ -310,7 +317,7 @@ class InternalBuilder {
|
|
|
310
317
|
delete(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
|
|
311
318
|
const { endpoint, filters } = json
|
|
312
319
|
let query: KnexQuery = knex(endpoint.entityId)
|
|
313
|
-
query = this.addFilters(endpoint.entityId
|
|
320
|
+
query = this.addFilters(query, filters, { tableName: endpoint.entityId })
|
|
314
321
|
// mysql can't use returning
|
|
315
322
|
if (opts.disableReturning) {
|
|
316
323
|
return query.delete()
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DatasourceFieldTypes,
|
|
3
|
+
Integration,
|
|
4
|
+
QueryJson,
|
|
5
|
+
QueryTypes,
|
|
6
|
+
} from "../definitions/datasource"
|
|
7
|
+
import { OAuth2Client } from "google-auth-library"
|
|
8
|
+
import { DatasourcePlus } from "./base/datasourcePlus"
|
|
9
|
+
import { Row, Table, TableSchema } from "../definitions/common"
|
|
10
|
+
import { buildExternalTableId } from "./utils"
|
|
11
|
+
import { DataSourceOperation, FieldTypes } from "../constants"
|
|
12
|
+
import { GoogleSpreadsheet } from "google-spreadsheet"
|
|
13
|
+
import { table } from "console"
|
|
14
|
+
|
|
15
|
+
module GoogleSheetsModule {
|
|
16
|
+
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
|
17
|
+
const { getScopedConfig } = require("@budibase/backend-core/db")
|
|
18
|
+
const { Configs } = require("@budibase/backend-core/constants")
|
|
19
|
+
|
|
20
|
+
interface GoogleSheetsConfig {
|
|
21
|
+
spreadsheetId: string
|
|
22
|
+
auth: OAuthClientConfig
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface OAuthClientConfig {
|
|
26
|
+
appId: string
|
|
27
|
+
accessToken: string
|
|
28
|
+
refreshToken: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const SCHEMA: Integration = {
|
|
32
|
+
plus: true,
|
|
33
|
+
auth: {
|
|
34
|
+
type: "google",
|
|
35
|
+
},
|
|
36
|
+
relationships: false,
|
|
37
|
+
docs: "https://developers.google.com/sheets/api/quickstart/nodejs",
|
|
38
|
+
description:
|
|
39
|
+
"Create and collaborate on online spreadsheets in real-time and from any device. ",
|
|
40
|
+
friendlyName: "Google Sheets",
|
|
41
|
+
datasource: {
|
|
42
|
+
spreadsheetId: {
|
|
43
|
+
type: DatasourceFieldTypes.STRING,
|
|
44
|
+
required: true,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
query: {
|
|
48
|
+
create: {
|
|
49
|
+
type: QueryTypes.FIELDS,
|
|
50
|
+
fields: {
|
|
51
|
+
sheet: {
|
|
52
|
+
type: DatasourceFieldTypes.STRING,
|
|
53
|
+
required: true,
|
|
54
|
+
},
|
|
55
|
+
row: {
|
|
56
|
+
type: QueryTypes.JSON,
|
|
57
|
+
required: true,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
read: {
|
|
62
|
+
type: QueryTypes.FIELDS,
|
|
63
|
+
fields: {
|
|
64
|
+
sheet: {
|
|
65
|
+
type: DatasourceFieldTypes.STRING,
|
|
66
|
+
required: true,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
update: {
|
|
71
|
+
type: QueryTypes.FIELDS,
|
|
72
|
+
fields: {
|
|
73
|
+
sheet: {
|
|
74
|
+
type: DatasourceFieldTypes.STRING,
|
|
75
|
+
required: true,
|
|
76
|
+
},
|
|
77
|
+
rowIndex: {
|
|
78
|
+
type: DatasourceFieldTypes.STRING,
|
|
79
|
+
required: true,
|
|
80
|
+
},
|
|
81
|
+
row: {
|
|
82
|
+
type: QueryTypes.JSON,
|
|
83
|
+
required: true,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
delete: {
|
|
88
|
+
type: QueryTypes.FIELDS,
|
|
89
|
+
fields: {
|
|
90
|
+
sheet: {
|
|
91
|
+
type: DatasourceFieldTypes.STRING,
|
|
92
|
+
required: true,
|
|
93
|
+
},
|
|
94
|
+
rowIndex: {
|
|
95
|
+
type: DatasourceFieldTypes.NUMBER,
|
|
96
|
+
required: true,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
class GoogleSheetsIntegration implements DatasourcePlus {
|
|
104
|
+
private readonly config: GoogleSheetsConfig
|
|
105
|
+
private client: any
|
|
106
|
+
public tables: Record<string, Table> = {}
|
|
107
|
+
public schemaErrors: Record<string, string> = {}
|
|
108
|
+
|
|
109
|
+
constructor(config: GoogleSheetsConfig) {
|
|
110
|
+
this.config = config
|
|
111
|
+
const spreadsheetId = this.cleanSpreadsheetUrl(this.config.spreadsheetId)
|
|
112
|
+
this.client = new GoogleSpreadsheet(spreadsheetId)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Pull the spreadsheet ID out from a valid google sheets URL
|
|
117
|
+
* @param spreadsheetId - the URL or standard spreadsheetId of the google sheet
|
|
118
|
+
* @returns spreadsheet Id of the google sheet
|
|
119
|
+
*/
|
|
120
|
+
cleanSpreadsheetUrl(spreadsheetId: string) {
|
|
121
|
+
if (!spreadsheetId) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"You must set a spreadsheet ID in your configuration to fetch tables."
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
const parts = spreadsheetId.split("/")
|
|
127
|
+
return parts.length > 5 ? parts[5] : spreadsheetId
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async connect() {
|
|
131
|
+
try {
|
|
132
|
+
// Initialise oAuth client
|
|
133
|
+
const db = getGlobalDB()
|
|
134
|
+
const googleConfig = await getScopedConfig(db, {
|
|
135
|
+
type: Configs.GOOGLE,
|
|
136
|
+
})
|
|
137
|
+
const oauthClient = new OAuth2Client({
|
|
138
|
+
clientId: googleConfig.clientID,
|
|
139
|
+
clientSecret: googleConfig.clientSecret,
|
|
140
|
+
})
|
|
141
|
+
oauthClient.credentials.access_token = this.config.auth.accessToken
|
|
142
|
+
oauthClient.credentials.refresh_token = this.config.auth.refreshToken
|
|
143
|
+
this.client.useOAuth2Client(oauthClient)
|
|
144
|
+
await this.client.loadInfo()
|
|
145
|
+
} catch (err) {
|
|
146
|
+
console.error("Error connecting to google sheets", err)
|
|
147
|
+
throw err
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async buildSchema(datasourceId: string) {
|
|
152
|
+
await this.connect()
|
|
153
|
+
const sheets = await this.client.sheetsByIndex
|
|
154
|
+
const tables: Record<string, Table> = {}
|
|
155
|
+
for (let sheet of sheets) {
|
|
156
|
+
// must fetch rows to determine schema
|
|
157
|
+
await sheet.getRows()
|
|
158
|
+
// build schema
|
|
159
|
+
const schema: TableSchema = {}
|
|
160
|
+
|
|
161
|
+
// build schema from headers
|
|
162
|
+
for (let header of sheet.headerValues) {
|
|
163
|
+
schema[header] = {
|
|
164
|
+
name: header,
|
|
165
|
+
type: FieldTypes.STRING,
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// create tables
|
|
170
|
+
tables[sheet.title] = {
|
|
171
|
+
_id: buildExternalTableId(datasourceId, sheet.title),
|
|
172
|
+
name: sheet.title,
|
|
173
|
+
primary: ["rowNumber"],
|
|
174
|
+
schema,
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.tables = tables
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async query(json: QueryJson) {
|
|
182
|
+
const sheet = json.endpoint.entityId
|
|
183
|
+
|
|
184
|
+
const handlers = {
|
|
185
|
+
[DataSourceOperation.CREATE]: () =>
|
|
186
|
+
this.create({ sheet, row: json.body }),
|
|
187
|
+
[DataSourceOperation.READ]: () => this.read({ sheet }),
|
|
188
|
+
[DataSourceOperation.UPDATE]: () =>
|
|
189
|
+
this.update({
|
|
190
|
+
// exclude the header row and zero index
|
|
191
|
+
rowIndex: json.extra?.idFilter?.equal?.rowNumber - 2,
|
|
192
|
+
sheet,
|
|
193
|
+
row: json.body,
|
|
194
|
+
}),
|
|
195
|
+
[DataSourceOperation.DELETE]: () =>
|
|
196
|
+
this.delete({
|
|
197
|
+
// exclude the header row and zero index
|
|
198
|
+
rowIndex: json.extra?.idFilter?.equal?.rowNumber - 2,
|
|
199
|
+
sheet,
|
|
200
|
+
}),
|
|
201
|
+
[DataSourceOperation.CREATE_TABLE]: () =>
|
|
202
|
+
this.createTable(json?.table?.name),
|
|
203
|
+
[DataSourceOperation.UPDATE_TABLE]: () => this.updateTable(json.table),
|
|
204
|
+
[DataSourceOperation.DELETE_TABLE]: () =>
|
|
205
|
+
this.deleteTable(json?.table?.name),
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const internalQueryMethod = handlers[json.endpoint.operation]
|
|
209
|
+
|
|
210
|
+
return await internalQueryMethod()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
buildRowObject(headers: string[], values: string[], rowNumber: number) {
|
|
214
|
+
const rowObject: { rowNumber: number; [key: string]: any } = { rowNumber }
|
|
215
|
+
for (let i = 0; i < headers.length; i++) {
|
|
216
|
+
rowObject._id = rowNumber
|
|
217
|
+
rowObject[headers[i]] = values[i]
|
|
218
|
+
}
|
|
219
|
+
return rowObject
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async createTable(name?: string) {
|
|
223
|
+
try {
|
|
224
|
+
await this.connect()
|
|
225
|
+
const sheet = await this.client.addSheet({ title: name })
|
|
226
|
+
return sheet
|
|
227
|
+
} catch (err) {
|
|
228
|
+
console.error("Error creating new table in google sheets", err)
|
|
229
|
+
throw err
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async updateTable(table?: any) {
|
|
234
|
+
try {
|
|
235
|
+
await this.connect()
|
|
236
|
+
const sheet = await this.client.sheetsByTitle[table.name]
|
|
237
|
+
await sheet.loadHeaderRow()
|
|
238
|
+
|
|
239
|
+
if (table._rename) {
|
|
240
|
+
const headers = []
|
|
241
|
+
for (let header of sheet.headerValues) {
|
|
242
|
+
if (header === table._rename.old) {
|
|
243
|
+
headers.push(table._rename.updated)
|
|
244
|
+
} else {
|
|
245
|
+
headers.push(header)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
await sheet.setHeaderRow(headers)
|
|
249
|
+
} else {
|
|
250
|
+
let newField = Object.keys(table.schema).find(
|
|
251
|
+
key => !sheet.headerValues.includes(key)
|
|
252
|
+
)
|
|
253
|
+
await sheet.setHeaderRow([...sheet.headerValues, newField])
|
|
254
|
+
}
|
|
255
|
+
} catch (err) {
|
|
256
|
+
console.error("Error updating table in google sheets", err)
|
|
257
|
+
throw err
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async deleteTable(sheet: any) {
|
|
262
|
+
try {
|
|
263
|
+
await this.connect()
|
|
264
|
+
const sheetToDelete = await this.client.sheetsByTitle[sheet]
|
|
265
|
+
return await sheetToDelete.delete()
|
|
266
|
+
} catch (err) {
|
|
267
|
+
console.error("Error deleting table in google sheets", err)
|
|
268
|
+
throw err
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async create(query: { sheet: string; row: any }) {
|
|
273
|
+
try {
|
|
274
|
+
await this.connect()
|
|
275
|
+
const sheet = await this.client.sheetsByTitle[query.sheet]
|
|
276
|
+
const rowToInsert =
|
|
277
|
+
typeof query.row === "string" ? JSON.parse(query.row) : query.row
|
|
278
|
+
const row = await sheet.addRow(rowToInsert)
|
|
279
|
+
return [
|
|
280
|
+
this.buildRowObject(sheet.headerValues, row._rawData, row._rowNumber),
|
|
281
|
+
]
|
|
282
|
+
} catch (err) {
|
|
283
|
+
console.error("Error writing to google sheets", err)
|
|
284
|
+
throw err
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async read(query: { sheet: string }) {
|
|
289
|
+
try {
|
|
290
|
+
await this.connect()
|
|
291
|
+
const sheet = await this.client.sheetsByTitle[query.sheet]
|
|
292
|
+
const rows = await sheet.getRows()
|
|
293
|
+
const headerValues = sheet.headerValues
|
|
294
|
+
const response = []
|
|
295
|
+
for (let row of rows) {
|
|
296
|
+
response.push(
|
|
297
|
+
this.buildRowObject(headerValues, row._rawData, row._rowNumber)
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
return response
|
|
301
|
+
} catch (err) {
|
|
302
|
+
console.error("Error reading from google sheets", err)
|
|
303
|
+
throw err
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async update(query: { sheet: string; rowIndex: number; row: any }) {
|
|
308
|
+
try {
|
|
309
|
+
await this.connect()
|
|
310
|
+
const sheet = await this.client.sheetsByTitle[query.sheet]
|
|
311
|
+
const rows = await sheet.getRows()
|
|
312
|
+
const row = rows[query.rowIndex]
|
|
313
|
+
if (row) {
|
|
314
|
+
const updateValues = query.row
|
|
315
|
+
for (let key in updateValues) {
|
|
316
|
+
row[key] = updateValues[key]
|
|
317
|
+
}
|
|
318
|
+
await row.save()
|
|
319
|
+
return [
|
|
320
|
+
this.buildRowObject(
|
|
321
|
+
sheet.headerValues,
|
|
322
|
+
row._rawData,
|
|
323
|
+
row._rowNumber
|
|
324
|
+
),
|
|
325
|
+
]
|
|
326
|
+
} else {
|
|
327
|
+
throw new Error("Row does not exist.")
|
|
328
|
+
}
|
|
329
|
+
} catch (err) {
|
|
330
|
+
console.error("Error reading from google sheets", err)
|
|
331
|
+
throw err
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async delete(query: { sheet: string; rowIndex: number }) {
|
|
336
|
+
await this.connect()
|
|
337
|
+
const sheet = await this.client.sheetsByTitle[query.sheet]
|
|
338
|
+
const rows = await sheet.getRows()
|
|
339
|
+
const row = rows[query.rowIndex]
|
|
340
|
+
if (row) {
|
|
341
|
+
await row.delete()
|
|
342
|
+
return [{ deleted: query.rowIndex }]
|
|
343
|
+
} else {
|
|
344
|
+
throw new Error("Row does not exist.")
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
module.exports = {
|
|
350
|
+
schema: SCHEMA,
|
|
351
|
+
integration: GoogleSheetsIntegration,
|
|
352
|
+
}
|
|
353
|
+
}
|
|
@@ -9,6 +9,7 @@ const airtable = require("./airtable")
|
|
|
9
9
|
const mysql = require("./mysql")
|
|
10
10
|
const arangodb = require("./arangodb")
|
|
11
11
|
const rest = require("./rest")
|
|
12
|
+
const googlesheets = require("./googlesheets")
|
|
12
13
|
const { SourceNames } = require("../definitions/datasource")
|
|
13
14
|
|
|
14
15
|
const DEFINITIONS = {
|
|
@@ -23,6 +24,7 @@ const DEFINITIONS = {
|
|
|
23
24
|
[SourceNames.MYSQL]: mysql.schema,
|
|
24
25
|
[SourceNames.ARANGODB]: arangodb.schema,
|
|
25
26
|
[SourceNames.REST]: rest.schema,
|
|
27
|
+
[SourceNames.GOOGLE_SHEETS]: googlesheets.schema,
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const INTEGRATIONS = {
|
|
@@ -37,6 +39,7 @@ const INTEGRATIONS = {
|
|
|
37
39
|
[SourceNames.MYSQL]: mysql.integration,
|
|
38
40
|
[SourceNames.ARANGODB]: arangodb.integration,
|
|
39
41
|
[SourceNames.REST]: rest.integration,
|
|
42
|
+
[SourceNames.GOOGLE_SHEETS]: googlesheets.integration,
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
// optionally add oracle integration if the oracle binary can be installed
|
|
@@ -119,6 +119,22 @@ describe("SQL query builder", () => {
|
|
|
119
119
|
})
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
+
it("should allow filtering on a related field", () => {
|
|
123
|
+
const query = sql._query(generateReadJson({
|
|
124
|
+
filters: {
|
|
125
|
+
equal: {
|
|
126
|
+
age: 10,
|
|
127
|
+
"task.name": "task 1",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
}))
|
|
131
|
+
// order of bindings changes because relationship filters occur outside inner query
|
|
132
|
+
expect(query).toEqual({
|
|
133
|
+
bindings: [10, limit, "task 1"],
|
|
134
|
+
sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."age" = $1 limit $2) as "${TABLE_NAME}" where "task"."name" = $3`
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
|
|
122
138
|
it("should test an create statement", () => {
|
|
123
139
|
const query = sql._query(generateCreateJson(TABLE_NAME, {
|
|
124
140
|
name: "Michael",
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { SqlQuery } from "../definitions/datasource"
|
|
1
|
+
import { SourceNames, SqlQuery } from "../definitions/datasource"
|
|
2
2
|
import { Datasource, Table } from "../definitions/common"
|
|
3
|
-
import { SourceNames } from "../definitions/datasource"
|
|
4
3
|
import { DocumentTypes, SEPARATOR } from "../db/utils"
|
|
5
4
|
import { FieldTypes, BuildSchemaErrors, InvalidColumns } from "../constants"
|
|
6
5
|
|
|
@@ -127,7 +126,12 @@ export function isSQL(datasource: Datasource): boolean {
|
|
|
127
126
|
if (!datasource || !datasource.source) {
|
|
128
127
|
return false
|
|
129
128
|
}
|
|
130
|
-
const SQL = [
|
|
129
|
+
const SQL = [
|
|
130
|
+
SourceNames.POSTGRES,
|
|
131
|
+
SourceNames.SQL_SERVER,
|
|
132
|
+
SourceNames.MYSQL,
|
|
133
|
+
SourceNames.ORACLE,
|
|
134
|
+
]
|
|
131
135
|
return SQL.indexOf(datasource.source) !== -1
|
|
132
136
|
}
|
|
133
137
|
|
|
@@ -139,11 +143,60 @@ export function isIsoDateString(str: string) {
|
|
|
139
143
|
return d.toISOString() === str
|
|
140
144
|
}
|
|
141
145
|
|
|
142
|
-
|
|
146
|
+
/**
|
|
147
|
+
* This function will determine whether a column is a relationship and whether it
|
|
148
|
+
* is currently valid. The reason for the validity check is that tables can be deleted
|
|
149
|
+
* outside of Budibase control and if this is the case it will break Budibase relationships.
|
|
150
|
+
* The tableIds is a list passed down from the main finalise tables function, which is
|
|
151
|
+
* based on the tables that have just been fetched. This will only really be used on subsequent
|
|
152
|
+
* fetches to the first one - if the user is periodically refreshing Budibase knowledge of tables.
|
|
153
|
+
* @param column The column to check, to see if it is a valid relationship.
|
|
154
|
+
* @param tableIds The IDs of the tables which currently exist.
|
|
155
|
+
*/
|
|
156
|
+
function shouldCopyRelationship(
|
|
157
|
+
column: { type: string; tableId?: string },
|
|
158
|
+
tableIds: [string]
|
|
159
|
+
) {
|
|
160
|
+
return (
|
|
161
|
+
column.type === FieldTypes.LINK &&
|
|
162
|
+
column.tableId &&
|
|
163
|
+
tableIds.includes(column.tableId)
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Similar function to the shouldCopyRelationship function, but instead this looks for options and boolean
|
|
169
|
+
* types. It is possible to switch a string -> options and a number -> boolean (and vice versus) need to make
|
|
170
|
+
* sure that these get copied over when tables are fetched. Also checks whether they are still valid, if a
|
|
171
|
+
* column has changed type in the external database then copying it over may not be possible.
|
|
172
|
+
* @param column The column to check for options or boolean type.
|
|
173
|
+
* @param fetchedColumn The fetched column to check for the type in the external database.
|
|
174
|
+
*/
|
|
175
|
+
function shouldCopySpecialColumn(
|
|
176
|
+
column: { type: string },
|
|
177
|
+
fetchedColumn: { type: string } | undefined
|
|
178
|
+
) {
|
|
179
|
+
return (
|
|
180
|
+
column.type === FieldTypes.OPTIONS ||
|
|
181
|
+
column.type === FieldTypes.ARRAY ||
|
|
182
|
+
((!fetchedColumn || fetchedColumn.type === FieldTypes.NUMBER) &&
|
|
183
|
+
column.type === FieldTypes.BOOLEAN)
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Looks for columns which need to be copied over into the new table definitions, like relationships
|
|
189
|
+
* and options types.
|
|
190
|
+
* @param tableName The name of the table which is being checked.
|
|
191
|
+
* @param table The specific table which is being checked.
|
|
192
|
+
* @param entities All the tables that existed before - the old table definitions.
|
|
193
|
+
* @param tableIds The IDs of the tables which exist now, to check if anything has been removed.
|
|
194
|
+
*/
|
|
143
195
|
function copyExistingPropsOver(
|
|
144
196
|
tableName: string,
|
|
145
197
|
table: Table,
|
|
146
|
-
entities: { [key: string]: any }
|
|
198
|
+
entities: { [key: string]: any },
|
|
199
|
+
tableIds: [string]
|
|
147
200
|
) {
|
|
148
201
|
if (entities && entities[tableName]) {
|
|
149
202
|
if (entities[tableName].primaryDisplay) {
|
|
@@ -154,11 +207,10 @@ function copyExistingPropsOver(
|
|
|
154
207
|
if (!existingTableSchema.hasOwnProperty(key)) {
|
|
155
208
|
continue
|
|
156
209
|
}
|
|
210
|
+
const column = existingTableSchema[key]
|
|
157
211
|
if (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
((!table.schema[key] || table.schema[key].type === FieldTypes.NUMBER) &&
|
|
161
|
-
existingTableSchema[key].type === FieldTypes.BOOLEAN)
|
|
212
|
+
shouldCopyRelationship(column, tableIds) ||
|
|
213
|
+
shouldCopySpecialColumn(column, table.schema[key])
|
|
162
214
|
) {
|
|
163
215
|
table.schema[key] = existingTableSchema[key]
|
|
164
216
|
}
|
|
@@ -167,6 +219,13 @@ function copyExistingPropsOver(
|
|
|
167
219
|
return table
|
|
168
220
|
}
|
|
169
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Look through the final table definitions to see if anything needs to be
|
|
224
|
+
* copied over from the old and if any errors have occurred mark them so
|
|
225
|
+
* that the user can be made aware.
|
|
226
|
+
* @param tables The list of tables that have been retrieved from the external database.
|
|
227
|
+
* @param entities The old list of tables, if there was any to look for definitions in.
|
|
228
|
+
*/
|
|
170
229
|
export function finaliseExternalTables(
|
|
171
230
|
tables: { [key: string]: any },
|
|
172
231
|
entities: { [key: string]: any }
|
|
@@ -174,6 +233,8 @@ export function finaliseExternalTables(
|
|
|
174
233
|
const invalidColumns = Object.values(InvalidColumns)
|
|
175
234
|
let finalTables: { [key: string]: any } = {}
|
|
176
235
|
const errors: { [key: string]: string } = {}
|
|
236
|
+
// @ts-ignore
|
|
237
|
+
const tableIds: [string] = Object.values(tables).map(table => table._id)
|
|
177
238
|
for (let [name, table] of Object.entries(tables)) {
|
|
178
239
|
const schemaFields = Object.keys(table.schema)
|
|
179
240
|
// make sure every table has a key
|
|
@@ -185,7 +246,7 @@ export function finaliseExternalTables(
|
|
|
185
246
|
continue
|
|
186
247
|
}
|
|
187
248
|
// make sure all previous props have been added back
|
|
188
|
-
finalTables[name] = copyExistingPropsOver(name, table, entities)
|
|
249
|
+
finalTables[name] = copyExistingPropsOver(name, table, entities, tableIds)
|
|
189
250
|
}
|
|
190
251
|
// sort the tables by name
|
|
191
252
|
finalTables = Object.entries(finalTables)
|