@budibase/backend-core 3.2.4 → 3.2.6
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/dist/index.js.map +1 -1
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +11 -4
- package/dist/plugins.js.meta.json +1 -1
- package/package.json +11 -4
- package/src/accounts/accounts.ts +0 -82
- package/src/accounts/api.ts +0 -59
- package/src/accounts/index.ts +0 -1
- package/src/auth/auth.ts +0 -210
- package/src/auth/index.ts +0 -1
- package/src/auth/tests/auth.spec.ts +0 -14
- package/src/blacklist/blacklist.ts +0 -54
- package/src/blacklist/index.ts +0 -1
- package/src/blacklist/tests/blacklist.spec.ts +0 -46
- package/src/cache/appMetadata.ts +0 -88
- package/src/cache/base/index.ts +0 -150
- package/src/cache/docWritethrough.ts +0 -105
- package/src/cache/generic.ts +0 -33
- package/src/cache/index.ts +0 -8
- package/src/cache/invite.ts +0 -86
- package/src/cache/passwordReset.ts +0 -49
- package/src/cache/tests/docWritethrough.spec.ts +0 -296
- package/src/cache/tests/user.spec.ts +0 -145
- package/src/cache/tests/writethrough.spec.ts +0 -139
- package/src/cache/user.ts +0 -154
- package/src/cache/writethrough.ts +0 -133
- package/src/configs/configs.ts +0 -263
- package/src/configs/index.ts +0 -1
- package/src/configs/tests/configs.spec.ts +0 -184
- package/src/constants/db.ts +0 -75
- package/src/constants/index.ts +0 -2
- package/src/constants/misc.ts +0 -36
- package/src/context/Context.ts +0 -14
- package/src/context/identity.ts +0 -58
- package/src/context/index.ts +0 -3
- package/src/context/mainContext.ts +0 -422
- package/src/context/tests/index.spec.ts +0 -255
- package/src/context/types.ts +0 -26
- package/src/db/Replication.ts +0 -94
- package/src/db/couch/DatabaseImpl.ts +0 -511
- package/src/db/couch/connections.ts +0 -89
- package/src/db/couch/index.ts +0 -4
- package/src/db/couch/pouchDB.ts +0 -97
- package/src/db/couch/pouchDump.ts +0 -0
- package/src/db/couch/tests/DatabaseImpl.spec.ts +0 -118
- package/src/db/couch/utils.ts +0 -55
- package/src/db/db.ts +0 -34
- package/src/db/errors.ts +0 -14
- package/src/db/index.ts +0 -12
- package/src/db/instrumentation.ts +0 -199
- package/src/db/lucene.ts +0 -721
- package/src/db/searchIndexes/index.ts +0 -1
- package/src/db/searchIndexes/searchIndexes.ts +0 -62
- package/src/db/tests/DatabaseImpl.spec.ts +0 -55
- package/src/db/tests/connections.spec.ts +0 -22
- package/src/db/tests/index.spec.ts +0 -32
- package/src/db/tests/lucene.spec.ts +0 -400
- package/src/db/tests/pouch.spec.js +0 -62
- package/src/db/tests/utils.spec.ts +0 -63
- package/src/db/utils.ts +0 -208
- package/src/db/views.ts +0 -245
- package/src/docIds/conversions.ts +0 -60
- package/src/docIds/ids.ts +0 -126
- package/src/docIds/index.ts +0 -2
- package/src/docIds/newid.ts +0 -5
- package/src/docIds/params.ts +0 -189
- package/src/docUpdates/index.ts +0 -24
- package/src/environment.ts +0 -293
- package/src/errors/errors.ts +0 -119
- package/src/errors/index.ts +0 -1
- package/src/events/analytics.ts +0 -6
- package/src/events/asyncEvents/index.ts +0 -2
- package/src/events/asyncEvents/publisher.ts +0 -12
- package/src/events/asyncEvents/queue.ts +0 -22
- package/src/events/backfill.ts +0 -183
- package/src/events/documentId.ts +0 -56
- package/src/events/events.ts +0 -47
- package/src/events/identification.ts +0 -311
- package/src/events/index.ts +0 -15
- package/src/events/processors/AnalyticsProcessor.ts +0 -64
- package/src/events/processors/AuditLogsProcessor.ts +0 -92
- package/src/events/processors/LoggingProcessor.ts +0 -36
- package/src/events/processors/Processors.ts +0 -52
- package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -38
- package/src/events/processors/index.ts +0 -19
- package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
- package/src/events/processors/posthog/index.ts +0 -3
- package/src/events/processors/posthog/rateLimiting.ts +0 -106
- package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -164
- package/src/events/processors/types.ts +0 -1
- package/src/events/publishers/account.ts +0 -41
- package/src/events/publishers/ai.ts +0 -21
- package/src/events/publishers/app.ts +0 -168
- package/src/events/publishers/auditLog.ts +0 -26
- package/src/events/publishers/auth.ts +0 -73
- package/src/events/publishers/automation.ts +0 -110
- package/src/events/publishers/backfill.ts +0 -74
- package/src/events/publishers/backup.ts +0 -42
- package/src/events/publishers/datasource.ts +0 -48
- package/src/events/publishers/email.ts +0 -17
- package/src/events/publishers/environmentVariable.ts +0 -38
- package/src/events/publishers/group.ts +0 -99
- package/src/events/publishers/index.ts +0 -25
- package/src/events/publishers/installation.ts +0 -38
- package/src/events/publishers/layout.ts +0 -26
- package/src/events/publishers/license.ts +0 -84
- package/src/events/publishers/org.ts +0 -37
- package/src/events/publishers/plugin.ts +0 -47
- package/src/events/publishers/query.ts +0 -89
- package/src/events/publishers/role.ts +0 -62
- package/src/events/publishers/rows.ts +0 -29
- package/src/events/publishers/screen.ts +0 -36
- package/src/events/publishers/serve.ts +0 -43
- package/src/events/publishers/table.ts +0 -70
- package/src/events/publishers/user.ts +0 -202
- package/src/events/publishers/view.ts +0 -107
- package/src/features/features.ts +0 -277
- package/src/features/index.ts +0 -2
- package/src/features/tests/features.spec.ts +0 -267
- package/src/features/tests/utils.ts +0 -64
- package/src/helpers.ts +0 -9
- package/src/index.ts +0 -59
- package/src/installation.ts +0 -115
- package/src/logging/alerts.ts +0 -26
- package/src/logging/correlation/correlation.ts +0 -15
- package/src/logging/correlation/index.ts +0 -1
- package/src/logging/correlation/middleware.ts +0 -18
- package/src/logging/index.ts +0 -4
- package/src/logging/pino/logger.ts +0 -239
- package/src/logging/pino/middleware.ts +0 -48
- package/src/logging/system.ts +0 -81
- package/src/logging/tests/system.spec.ts +0 -61
- package/src/middleware/adminOnly.ts +0 -9
- package/src/middleware/auditLog.ts +0 -6
- package/src/middleware/authenticated.ts +0 -247
- package/src/middleware/builderOnly.ts +0 -21
- package/src/middleware/builderOrAdmin.ts +0 -21
- package/src/middleware/contentSecurityPolicy.ts +0 -113
- package/src/middleware/csrf.ts +0 -81
- package/src/middleware/errorHandling.ts +0 -43
- package/src/middleware/index.ts +0 -24
- package/src/middleware/internalApi.ts +0 -23
- package/src/middleware/ip.ts +0 -12
- package/src/middleware/joi-validator.ts +0 -58
- package/src/middleware/matchers.ts +0 -39
- package/src/middleware/passport/datasource/google.ts +0 -102
- package/src/middleware/passport/local.ts +0 -54
- package/src/middleware/passport/sso/google.ts +0 -77
- package/src/middleware/passport/sso/oidc.ts +0 -152
- package/src/middleware/passport/sso/sso.ts +0 -138
- package/src/middleware/passport/sso/tests/google.spec.ts +0 -68
- package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -144
- package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
- package/src/middleware/passport/utils.ts +0 -38
- package/src/middleware/querystringToBody.ts +0 -28
- package/src/middleware/tenancy.ts +0 -36
- package/src/middleware/tests/builder.spec.ts +0 -181
- package/src/middleware/tests/contentSecurityPolicy.spec.ts +0 -75
- package/src/middleware/tests/matchers.spec.ts +0 -100
- package/src/migrations/definitions.ts +0 -40
- package/src/migrations/index.ts +0 -2
- package/src/migrations/migrations.ts +0 -186
- package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
- package/src/migrations/tests/migrations.spec.ts +0 -64
- package/src/objectStore/buckets/app.ts +0 -53
- package/src/objectStore/buckets/global.ts +0 -29
- package/src/objectStore/buckets/index.ts +0 -3
- package/src/objectStore/buckets/plugins.ts +0 -71
- package/src/objectStore/buckets/tests/app.spec.ts +0 -161
- package/src/objectStore/buckets/tests/global.spec.ts +0 -74
- package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
- package/src/objectStore/cloudfront.ts +0 -41
- package/src/objectStore/index.ts +0 -3
- package/src/objectStore/objectStore.ts +0 -585
- package/src/objectStore/utils.ts +0 -113
- package/src/platform/index.ts +0 -3
- package/src/platform/platformDb.ts +0 -6
- package/src/platform/tenants.ts +0 -101
- package/src/platform/tests/tenants.spec.ts +0 -26
- package/src/platform/users.ts +0 -129
- package/src/plugin/index.ts +0 -1
- package/src/plugin/tests/validation.spec.ts +0 -209
- package/src/plugin/utils.ts +0 -175
- package/src/queue/constants.ts +0 -8
- package/src/queue/inMemoryQueue.ts +0 -189
- package/src/queue/index.ts +0 -2
- package/src/queue/listeners.ts +0 -199
- package/src/queue/queue.ts +0 -84
- package/src/redis/index.ts +0 -6
- package/src/redis/init.ts +0 -118
- package/src/redis/redis.ts +0 -358
- package/src/redis/redlockImpl.ts +0 -155
- package/src/redis/tests/redis.spec.ts +0 -207
- package/src/redis/tests/redlockImpl.spec.ts +0 -105
- package/src/redis/utils.ts +0 -128
- package/src/security/auth.ts +0 -24
- package/src/security/encryption.ts +0 -185
- package/src/security/index.ts +0 -1
- package/src/security/permissions.ts +0 -166
- package/src/security/roles.ts +0 -655
- package/src/security/secrets.ts +0 -20
- package/src/security/sessions.ts +0 -123
- package/src/security/tests/auth.spec.ts +0 -45
- package/src/security/tests/encryption.spec.ts +0 -31
- package/src/security/tests/permissions.spec.ts +0 -146
- package/src/security/tests/secrets.spec.ts +0 -35
- package/src/security/tests/sessions.spec.ts +0 -12
- package/src/sql/designDoc.ts +0 -17
- package/src/sql/index.ts +0 -5
- package/src/sql/sql.ts +0 -1854
- package/src/sql/sqlTable.ts +0 -319
- package/src/sql/utils.ts +0 -193
- package/src/tenancy/db.ts +0 -6
- package/src/tenancy/index.ts +0 -2
- package/src/tenancy/tenancy.ts +0 -148
- package/src/tenancy/tests/tenancy.spec.ts +0 -184
- package/src/timers/index.ts +0 -1
- package/src/timers/timers.ts +0 -22
- package/src/users/db.ts +0 -582
- package/src/users/events.ts +0 -176
- package/src/users/index.ts +0 -4
- package/src/users/lookup.ts +0 -99
- package/src/users/test/db.spec.ts +0 -188
- package/src/users/test/utils.spec.ts +0 -67
- package/src/users/users.ts +0 -353
- package/src/users/utils.ts +0 -81
- package/src/utils/Duration.ts +0 -56
- package/src/utils/hashing.ts +0 -15
- package/src/utils/index.ts +0 -4
- package/src/utils/stringUtils.ts +0 -8
- package/src/utils/tests/Duration.spec.ts +0 -19
- package/src/utils/tests/utils.spec.ts +0 -204
- package/src/utils/utils.ts +0 -249
- package/tests/core/logging.ts +0 -34
- package/tests/core/users/users.spec.js +0 -53
- package/tests/core/utilities/index.ts +0 -7
- package/tests/core/utilities/jestUtils.ts +0 -33
- package/tests/core/utilities/mocks/alerts.ts +0 -4
- package/tests/core/utilities/mocks/date.ts +0 -3
- package/tests/core/utilities/mocks/events.ts +0 -132
- package/tests/core/utilities/mocks/index.ts +0 -9
- package/tests/core/utilities/mocks/licenses.ts +0 -119
- package/tests/core/utilities/queue.ts +0 -9
- package/tests/core/utilities/structures/Chance.ts +0 -20
- package/tests/core/utilities/structures/accounts.ts +0 -80
- package/tests/core/utilities/structures/apps.ts +0 -21
- package/tests/core/utilities/structures/common.ts +0 -7
- package/tests/core/utilities/structures/db.ts +0 -12
- package/tests/core/utilities/structures/documents/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
- package/tests/core/utilities/structures/generator.ts +0 -3
- package/tests/core/utilities/structures/index.ts +0 -15
- package/tests/core/utilities/structures/koa.ts +0 -16
- package/tests/core/utilities/structures/licenses.ts +0 -190
- package/tests/core/utilities/structures/plugins.ts +0 -19
- package/tests/core/utilities/structures/quotas.ts +0 -72
- package/tests/core/utilities/structures/scim.ts +0 -80
- package/tests/core/utilities/structures/sso.ts +0 -118
- package/tests/core/utilities/structures/tenants.ts +0 -5
- package/tests/core/utilities/structures/userGroups.ts +0 -10
- package/tests/core/utilities/structures/users.ts +0 -89
- package/tests/core/utilities/testContainerUtils.ts +0 -165
- package/tests/core/utilities/utils/index.ts +0 -2
- package/tests/core/utilities/utils/queue.ts +0 -27
- package/tests/core/utilities/utils/time.ts +0 -3
- package/tests/extra/DBTestConfiguration.ts +0 -36
- package/tests/extra/index.ts +0 -2
- package/tests/extra/testEnv.ts +0 -95
- package/tests/index.ts +0 -2
- package/tests/jestEnv.ts +0 -10
- package/tests/jestSetup.ts +0 -36
package/src/sql/sqlTable.ts
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import { Knex, knex } from "knex"
|
|
2
|
-
import {
|
|
3
|
-
FieldType,
|
|
4
|
-
NumberFieldMetadata,
|
|
5
|
-
Operation,
|
|
6
|
-
QueryJson,
|
|
7
|
-
RelationshipType,
|
|
8
|
-
RenameColumn,
|
|
9
|
-
SqlQuery,
|
|
10
|
-
Table,
|
|
11
|
-
TableSourceType,
|
|
12
|
-
SqlClient,
|
|
13
|
-
} from "@budibase/types"
|
|
14
|
-
import { breakExternalTableId, getNativeSql } from "./utils"
|
|
15
|
-
import { helpers, utils } from "@budibase/shared-core"
|
|
16
|
-
import SchemaBuilder = Knex.SchemaBuilder
|
|
17
|
-
import CreateTableBuilder = Knex.CreateTableBuilder
|
|
18
|
-
|
|
19
|
-
function isIgnoredType(type: FieldType) {
|
|
20
|
-
const ignored = [FieldType.LINK, FieldType.FORMULA, FieldType.AI]
|
|
21
|
-
return ignored.indexOf(type) !== -1
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function generateSchema(
|
|
25
|
-
schema: CreateTableBuilder,
|
|
26
|
-
table: Table,
|
|
27
|
-
tables: Record<string, Table>,
|
|
28
|
-
oldTable: null | Table = null,
|
|
29
|
-
renamed?: RenameColumn
|
|
30
|
-
) {
|
|
31
|
-
let primaryKeys = table && table.primary ? table.primary : []
|
|
32
|
-
const columns = Object.values(table.schema)
|
|
33
|
-
// all columns in a junction table will be meta
|
|
34
|
-
let metaCols = columns.filter(col => (col as NumberFieldMetadata).meta)
|
|
35
|
-
let isJunction = metaCols.length === columns.length
|
|
36
|
-
let columnTypeSet: string[] = []
|
|
37
|
-
|
|
38
|
-
// can't change primary once its set for now
|
|
39
|
-
if (!oldTable) {
|
|
40
|
-
// junction tables are special - we have an expected format
|
|
41
|
-
if (isJunction) {
|
|
42
|
-
schema.primary(metaCols.map(col => col.name))
|
|
43
|
-
} else if (primaryKeys.length === 1) {
|
|
44
|
-
schema.increments(primaryKeys[0]).primary()
|
|
45
|
-
// note that we've set its type
|
|
46
|
-
columnTypeSet.push(primaryKeys[0])
|
|
47
|
-
} else {
|
|
48
|
-
schema.primary(primaryKeys)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// check if any columns need added
|
|
53
|
-
const foreignKeys = Object.values(table.schema).map(
|
|
54
|
-
col => (col as any).foreignKey
|
|
55
|
-
)
|
|
56
|
-
for (let [key, column] of Object.entries(table.schema)) {
|
|
57
|
-
// skip things that are already correct
|
|
58
|
-
const oldColumn = oldTable ? oldTable.schema[key] : null
|
|
59
|
-
if (
|
|
60
|
-
(oldColumn && oldColumn.type) ||
|
|
61
|
-
columnTypeSet.includes(key) ||
|
|
62
|
-
renamed?.updated === key
|
|
63
|
-
) {
|
|
64
|
-
continue
|
|
65
|
-
}
|
|
66
|
-
const columnType = column.type
|
|
67
|
-
switch (columnType) {
|
|
68
|
-
case FieldType.STRING:
|
|
69
|
-
case FieldType.OPTIONS:
|
|
70
|
-
case FieldType.LONGFORM:
|
|
71
|
-
case FieldType.BARCODEQR:
|
|
72
|
-
case FieldType.BB_REFERENCE_SINGLE:
|
|
73
|
-
// primary key strings have to have a length in some DBs
|
|
74
|
-
if (primaryKeys.includes(key)) {
|
|
75
|
-
schema.string(key, 255)
|
|
76
|
-
} else {
|
|
77
|
-
schema.text(key)
|
|
78
|
-
}
|
|
79
|
-
break
|
|
80
|
-
case FieldType.NUMBER:
|
|
81
|
-
// if meta is specified then this is a junction table entry
|
|
82
|
-
if (column.meta && column.meta.toKey && column.meta.toTable) {
|
|
83
|
-
const { toKey, toTable } = column.meta
|
|
84
|
-
schema.integer(key).unsigned()
|
|
85
|
-
schema.foreign(key).references(`${toTable}.${toKey}`)
|
|
86
|
-
} else if (foreignKeys.indexOf(key) === -1) {
|
|
87
|
-
schema.float(key)
|
|
88
|
-
}
|
|
89
|
-
break
|
|
90
|
-
case FieldType.BIGINT:
|
|
91
|
-
schema.bigint(key)
|
|
92
|
-
break
|
|
93
|
-
case FieldType.BOOLEAN:
|
|
94
|
-
schema.boolean(key)
|
|
95
|
-
break
|
|
96
|
-
case FieldType.DATETIME:
|
|
97
|
-
if (!column.timeOnly) {
|
|
98
|
-
schema.datetime(key, {
|
|
99
|
-
useTz: !column.ignoreTimezones,
|
|
100
|
-
})
|
|
101
|
-
} else {
|
|
102
|
-
schema.time(key)
|
|
103
|
-
}
|
|
104
|
-
break
|
|
105
|
-
case FieldType.ARRAY:
|
|
106
|
-
case FieldType.BB_REFERENCE:
|
|
107
|
-
if (helpers.schema.isDeprecatedSingleUserColumn(column)) {
|
|
108
|
-
// This is still required for unit testing, in order to create "deprecated" schemas
|
|
109
|
-
schema.text(key)
|
|
110
|
-
} else {
|
|
111
|
-
schema.json(key)
|
|
112
|
-
}
|
|
113
|
-
break
|
|
114
|
-
case FieldType.LINK:
|
|
115
|
-
// this side of the relationship doesn't need any SQL work
|
|
116
|
-
if (
|
|
117
|
-
column.relationshipType !== RelationshipType.MANY_TO_ONE &&
|
|
118
|
-
column.relationshipType !== RelationshipType.MANY_TO_MANY
|
|
119
|
-
) {
|
|
120
|
-
if (!column.foreignKey || !column.tableId) {
|
|
121
|
-
throw new Error("Invalid relationship schema")
|
|
122
|
-
}
|
|
123
|
-
const { tableName } = breakExternalTableId(column.tableId)
|
|
124
|
-
// @ts-ignore
|
|
125
|
-
const relatedTable = tables[tableName]
|
|
126
|
-
if (!relatedTable || !relatedTable.primary) {
|
|
127
|
-
throw new Error(
|
|
128
|
-
"Referenced table doesn't exist or has no primary keys"
|
|
129
|
-
)
|
|
130
|
-
}
|
|
131
|
-
const relatedPrimary = relatedTable.primary[0]
|
|
132
|
-
const externalType = relatedTable.schema[relatedPrimary].externalType
|
|
133
|
-
if (externalType) {
|
|
134
|
-
schema.specificType(column.foreignKey, externalType)
|
|
135
|
-
} else {
|
|
136
|
-
schema.integer(column.foreignKey).unsigned()
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
schema
|
|
140
|
-
.foreign(column.foreignKey)
|
|
141
|
-
.references(`${tableName}.${relatedPrimary}`)
|
|
142
|
-
}
|
|
143
|
-
break
|
|
144
|
-
case FieldType.FORMULA:
|
|
145
|
-
// This is allowed, but nothing to do on the external datasource
|
|
146
|
-
break
|
|
147
|
-
case FieldType.AI:
|
|
148
|
-
// This is allowed, but nothing to do on the external datasource
|
|
149
|
-
break
|
|
150
|
-
case FieldType.ATTACHMENTS:
|
|
151
|
-
case FieldType.ATTACHMENT_SINGLE:
|
|
152
|
-
case FieldType.SIGNATURE_SINGLE:
|
|
153
|
-
case FieldType.AUTO:
|
|
154
|
-
case FieldType.JSON:
|
|
155
|
-
case FieldType.INTERNAL:
|
|
156
|
-
throw `${column.type} is not a valid SQL type`
|
|
157
|
-
|
|
158
|
-
default:
|
|
159
|
-
utils.unreachable(columnType)
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const oldType = renamed ? oldTable?.schema[renamed.old].type : undefined
|
|
164
|
-
if (renamed && oldType && !isIgnoredType(oldType)) {
|
|
165
|
-
schema.renameColumn(renamed.old, renamed.updated)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// need to check if any columns have been deleted
|
|
169
|
-
if (oldTable) {
|
|
170
|
-
const deletedColumns = Object.entries(oldTable.schema).filter(
|
|
171
|
-
([key, column]) =>
|
|
172
|
-
!isIgnoredType(column.type) && table.schema[key] == null
|
|
173
|
-
)
|
|
174
|
-
deletedColumns.forEach(([key, column]) => {
|
|
175
|
-
if (renamed?.old === key || isIgnoredType(column.type)) {
|
|
176
|
-
return
|
|
177
|
-
}
|
|
178
|
-
if (oldTable.constrained && oldTable.constrained.indexOf(key) !== -1) {
|
|
179
|
-
schema.dropForeign(key)
|
|
180
|
-
}
|
|
181
|
-
schema.dropColumn(key)
|
|
182
|
-
})
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return schema
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function buildCreateTable(
|
|
189
|
-
knex: SchemaBuilder,
|
|
190
|
-
table: Table,
|
|
191
|
-
tables: Record<string, Table>
|
|
192
|
-
): SchemaBuilder {
|
|
193
|
-
return knex.createTable(table.name, schema => {
|
|
194
|
-
generateSchema(schema, table, tables)
|
|
195
|
-
})
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function buildUpdateTable(
|
|
199
|
-
knex: SchemaBuilder,
|
|
200
|
-
table: Table,
|
|
201
|
-
tables: Record<string, Table>,
|
|
202
|
-
oldTable: Table,
|
|
203
|
-
renamed: RenameColumn
|
|
204
|
-
): SchemaBuilder {
|
|
205
|
-
return knex.alterTable(table.name, schema => {
|
|
206
|
-
generateSchema(schema, table, tables, oldTable, renamed)
|
|
207
|
-
})
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function buildDeleteTable(knex: SchemaBuilder, table: Table): SchemaBuilder {
|
|
211
|
-
return knex.dropTable(table.name)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
class SqlTableQueryBuilder {
|
|
215
|
-
private readonly sqlClient: SqlClient
|
|
216
|
-
private extendedSqlClient: SqlClient | undefined
|
|
217
|
-
|
|
218
|
-
// pass through client to get flavour of SQL
|
|
219
|
-
constructor(client: SqlClient) {
|
|
220
|
-
this.sqlClient = client
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
getBaseSqlClient(): SqlClient {
|
|
224
|
-
return this.sqlClient
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
getSqlClient(): SqlClient {
|
|
228
|
-
return this.extendedSqlClient || this.sqlClient
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// if working in a database like MySQL with many variants (MariaDB)
|
|
232
|
-
// we can set another client which overrides the base one
|
|
233
|
-
setExtendedSqlClient(client: SqlClient) {
|
|
234
|
-
this.extendedSqlClient = client
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* @param json the input JSON structure from which an SQL query will be built.
|
|
239
|
-
* @return the operation that was found in the JSON.
|
|
240
|
-
*/
|
|
241
|
-
_operation(json: QueryJson): Operation {
|
|
242
|
-
return json.endpoint.operation
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
_tableQuery(json: QueryJson): SqlQuery | SqlQuery[] {
|
|
246
|
-
let client = knex({ client: this.sqlClient }).schema
|
|
247
|
-
let schemaName = json?.endpoint?.schema
|
|
248
|
-
if (schemaName) {
|
|
249
|
-
client = client.withSchema(schemaName)
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
let query: Knex.SchemaBuilder
|
|
253
|
-
if (!json.table || !json.meta || !json.meta.tables) {
|
|
254
|
-
throw new Error("Cannot execute without table being specified")
|
|
255
|
-
}
|
|
256
|
-
if (json.table.sourceType === TableSourceType.INTERNAL) {
|
|
257
|
-
throw new Error("Cannot perform table actions for SQS.")
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
switch (this._operation(json)) {
|
|
261
|
-
case Operation.CREATE_TABLE:
|
|
262
|
-
query = buildCreateTable(client, json.table, json.meta.tables)
|
|
263
|
-
break
|
|
264
|
-
case Operation.UPDATE_TABLE:
|
|
265
|
-
if (!json.meta || !json.meta.table) {
|
|
266
|
-
throw new Error("Must specify old table for update")
|
|
267
|
-
}
|
|
268
|
-
// renameColumn does not work for MySQL, so return a raw query
|
|
269
|
-
if (this.sqlClient === SqlClient.MY_SQL && json.meta.renamed) {
|
|
270
|
-
const updatedColumn = json.meta.renamed.updated
|
|
271
|
-
const tableName = schemaName
|
|
272
|
-
? `\`${schemaName}\`.\`${json.table.name}\``
|
|
273
|
-
: `\`${json.table.name}\``
|
|
274
|
-
return {
|
|
275
|
-
sql: `alter table ${tableName} rename column \`${json.meta.renamed.old}\` to \`${updatedColumn}\`;`,
|
|
276
|
-
bindings: [],
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
query = buildUpdateTable(
|
|
281
|
-
client,
|
|
282
|
-
json.table,
|
|
283
|
-
json.meta.tables,
|
|
284
|
-
json.meta.table,
|
|
285
|
-
json.meta.renamed!
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
// renameColumn for SQL Server returns a parameterised `sp_rename` query,
|
|
289
|
-
// which is not supported by SQL Server and gives a syntax error.
|
|
290
|
-
if (this.sqlClient === SqlClient.MS_SQL && json.meta.renamed) {
|
|
291
|
-
const oldColumn = json.meta.renamed.old
|
|
292
|
-
const updatedColumn = json.meta.renamed.updated
|
|
293
|
-
const tableName = schemaName
|
|
294
|
-
? `${schemaName}.${json.table.name}`
|
|
295
|
-
: `${json.table.name}`
|
|
296
|
-
const sql = getNativeSql(query)
|
|
297
|
-
if (Array.isArray(sql)) {
|
|
298
|
-
for (const query of sql) {
|
|
299
|
-
if (query.sql.startsWith("exec sp_rename")) {
|
|
300
|
-
query.sql = `exec sp_rename '${tableName}.${oldColumn}', '${updatedColumn}', 'COLUMN'`
|
|
301
|
-
query.bindings = []
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return sql
|
|
307
|
-
}
|
|
308
|
-
break
|
|
309
|
-
case Operation.DELETE_TABLE:
|
|
310
|
-
query = buildDeleteTable(client, json.table)
|
|
311
|
-
break
|
|
312
|
-
default:
|
|
313
|
-
throw new Error("Table operation is of unknown type")
|
|
314
|
-
}
|
|
315
|
-
return getNativeSql(query)
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
export default SqlTableQueryBuilder
|
package/src/sql/utils.ts
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DocumentType,
|
|
3
|
-
ManyToManyRelationshipJson,
|
|
4
|
-
RelationshipsJson,
|
|
5
|
-
SqlQuery,
|
|
6
|
-
Table,
|
|
7
|
-
TableSourceType,
|
|
8
|
-
} from "@budibase/types"
|
|
9
|
-
import { DEFAULT_BB_DATASOURCE_ID } from "../constants"
|
|
10
|
-
import { Knex } from "knex"
|
|
11
|
-
import { SEPARATOR } from "../db"
|
|
12
|
-
import environment from "../environment"
|
|
13
|
-
|
|
14
|
-
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
|
|
15
|
-
const ROW_ID_REGEX = /^\[.*]$/g
|
|
16
|
-
const ENCODED_SPACE = encodeURIComponent(" ")
|
|
17
|
-
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/
|
|
18
|
-
const TIME_REGEX = /^(?:\d{2}:)?(?:\d{2}:)(?:\d{2})$/
|
|
19
|
-
|
|
20
|
-
export function isExternalTableID(tableId: string) {
|
|
21
|
-
return tableId.startsWith(DocumentType.DATASOURCE + SEPARATOR)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function isInternalTableID(tableId: string) {
|
|
25
|
-
return !isExternalTableID(tableId)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function getNativeSql(
|
|
29
|
-
query: Knex.SchemaBuilder | Knex.QueryBuilder
|
|
30
|
-
): SqlQuery | SqlQuery[] {
|
|
31
|
-
let sql = query.toSQL()
|
|
32
|
-
|
|
33
|
-
if (Array.isArray(sql)) {
|
|
34
|
-
return sql as SqlQuery[]
|
|
35
|
-
}
|
|
36
|
-
let native: Knex.SqlNative | undefined
|
|
37
|
-
if (sql.toNative) {
|
|
38
|
-
native = sql.toNative()
|
|
39
|
-
}
|
|
40
|
-
return {
|
|
41
|
-
sql: native?.sql || sql.sql,
|
|
42
|
-
bindings: native?.bindings || sql.bindings,
|
|
43
|
-
} as SqlQuery
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function isExternalTable(table: Table) {
|
|
47
|
-
if (
|
|
48
|
-
table?.sourceId &&
|
|
49
|
-
table.sourceId.includes(DocumentType.DATASOURCE + SEPARATOR) &&
|
|
50
|
-
table?.sourceId !== DEFAULT_BB_DATASOURCE_ID
|
|
51
|
-
) {
|
|
52
|
-
return true
|
|
53
|
-
} else if (table?.sourceType === TableSourceType.EXTERNAL) {
|
|
54
|
-
return true
|
|
55
|
-
} else if (table?._id && isExternalTableID(table._id)) {
|
|
56
|
-
return true
|
|
57
|
-
}
|
|
58
|
-
return false
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function buildExternalTableId(datasourceId: string, tableName: string) {
|
|
62
|
-
// encode spaces
|
|
63
|
-
if (tableName.includes(" ")) {
|
|
64
|
-
tableName = encodeURIComponent(tableName)
|
|
65
|
-
}
|
|
66
|
-
return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}`
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function breakExternalTableId(tableId: string) {
|
|
70
|
-
const parts = tableId.split(DOUBLE_SEPARATOR)
|
|
71
|
-
let datasourceId = parts.shift()
|
|
72
|
-
// if they need joined
|
|
73
|
-
let tableName = parts.join(DOUBLE_SEPARATOR)
|
|
74
|
-
// if contains encoded spaces, decode it
|
|
75
|
-
if (tableName.includes(ENCODED_SPACE)) {
|
|
76
|
-
tableName = decodeURIComponent(tableName)
|
|
77
|
-
}
|
|
78
|
-
if (!datasourceId || !tableName) {
|
|
79
|
-
throw new Error("Unable to get datasource/table name from table ID")
|
|
80
|
-
}
|
|
81
|
-
return { datasourceId, tableName }
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function generateRowIdField(keyProps: any[] = []) {
|
|
85
|
-
if (!Array.isArray(keyProps)) {
|
|
86
|
-
keyProps = [keyProps]
|
|
87
|
-
}
|
|
88
|
-
for (let index in keyProps) {
|
|
89
|
-
if (keyProps[index] instanceof Buffer) {
|
|
90
|
-
keyProps[index] = keyProps[index].toString()
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// this conserves order and types
|
|
94
|
-
// we have to swap the double quotes to single quotes for use in HBS statements
|
|
95
|
-
// when using the literal helper the double quotes can break things
|
|
96
|
-
return encodeURIComponent(JSON.stringify(keyProps).replace(/"/g, "'"))
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function isRowId(field: any) {
|
|
100
|
-
return (
|
|
101
|
-
Array.isArray(field) ||
|
|
102
|
-
(typeof field === "string" && field.match(ROW_ID_REGEX) != null)
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function convertRowId(field: any) {
|
|
107
|
-
if (Array.isArray(field)) {
|
|
108
|
-
return field[0]
|
|
109
|
-
}
|
|
110
|
-
if (typeof field === "string" && field.match(ROW_ID_REGEX) != null) {
|
|
111
|
-
return field.substring(1, field.length - 1)
|
|
112
|
-
}
|
|
113
|
-
return field
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// should always return an array
|
|
117
|
-
export function breakRowIdField(_id: string | { _id: string }): any[] {
|
|
118
|
-
if (!_id) {
|
|
119
|
-
return []
|
|
120
|
-
}
|
|
121
|
-
// have to replace on the way back as we swapped out the double quotes
|
|
122
|
-
// when encoding, but JSON can't handle the single quotes
|
|
123
|
-
const id = typeof _id === "string" ? _id : _id._id
|
|
124
|
-
const decoded: string = decodeURIComponent(id).replace(/'/g, '"')
|
|
125
|
-
try {
|
|
126
|
-
const parsed = JSON.parse(decoded)
|
|
127
|
-
return Array.isArray(parsed) ? parsed : [parsed]
|
|
128
|
-
} catch (err) {
|
|
129
|
-
// wasn't json - likely was handlebars for a many to many
|
|
130
|
-
return [_id]
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function isInvalidISODateString(str: string) {
|
|
135
|
-
const trimmedValue = str.trim()
|
|
136
|
-
if (!ISO_DATE_REGEX.test(trimmedValue)) {
|
|
137
|
-
return false
|
|
138
|
-
}
|
|
139
|
-
let d = new Date(trimmedValue)
|
|
140
|
-
return isNaN(d.getTime())
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export function isValidISODateString(str: string) {
|
|
144
|
-
const trimmedValue = str.trim()
|
|
145
|
-
if (!ISO_DATE_REGEX.test(trimmedValue)) {
|
|
146
|
-
return false
|
|
147
|
-
}
|
|
148
|
-
let d = new Date(trimmedValue)
|
|
149
|
-
if (isNaN(d.getTime())) {
|
|
150
|
-
return false
|
|
151
|
-
}
|
|
152
|
-
return d.toISOString() === trimmedValue
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function isValidFilter(value: any) {
|
|
156
|
-
return value != null && value !== ""
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function isValidTime(value: string) {
|
|
160
|
-
return TIME_REGEX.test(value)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export function sqlLog(client: string, query: string, values?: any[]) {
|
|
164
|
-
if (!environment.SQL_LOGGING_ENABLE) {
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
let string = `[SQL] [${client.toUpperCase()}] query="${query}"`
|
|
168
|
-
if (values) {
|
|
169
|
-
string += ` values="${values.join(", ")}"`
|
|
170
|
-
}
|
|
171
|
-
console.log(string)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function isValidManyToManyRelationship(
|
|
175
|
-
relationship: RelationshipsJson
|
|
176
|
-
): relationship is ManyToManyRelationshipJson {
|
|
177
|
-
return (
|
|
178
|
-
!!relationship.through &&
|
|
179
|
-
!!relationship.fromPrimary &&
|
|
180
|
-
!!relationship.from &&
|
|
181
|
-
!!relationship.toPrimary &&
|
|
182
|
-
!!relationship.to
|
|
183
|
-
)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export function validateManyToMany(
|
|
187
|
-
relationship: RelationshipsJson
|
|
188
|
-
): ManyToManyRelationshipJson | undefined {
|
|
189
|
-
if (isValidManyToManyRelationship(relationship)) {
|
|
190
|
-
return relationship
|
|
191
|
-
}
|
|
192
|
-
return undefined
|
|
193
|
-
}
|
package/src/tenancy/db.ts
DELETED
package/src/tenancy/index.ts
DELETED
package/src/tenancy/tenancy.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DEFAULT_TENANT_ID,
|
|
3
|
-
getTenantId,
|
|
4
|
-
getTenantIDFromAppID,
|
|
5
|
-
isMultiTenant,
|
|
6
|
-
getPlatformURL,
|
|
7
|
-
} from "../context"
|
|
8
|
-
import {
|
|
9
|
-
BBContext,
|
|
10
|
-
TenantResolutionStrategy,
|
|
11
|
-
GetTenantIdOptions,
|
|
12
|
-
} from "@budibase/types"
|
|
13
|
-
import { Header } from "../constants"
|
|
14
|
-
|
|
15
|
-
export function addTenantToUrl(url: string) {
|
|
16
|
-
const tenantId = getTenantId()
|
|
17
|
-
|
|
18
|
-
if (isMultiTenant()) {
|
|
19
|
-
const char = url.indexOf("?") === -1 ? "?" : "&"
|
|
20
|
-
url += `${char}tenantId=${tenantId}`
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return url
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const isUserInAppTenant = (appId: string, user?: any) => {
|
|
27
|
-
let userTenantId
|
|
28
|
-
if (user) {
|
|
29
|
-
userTenantId = user.tenantId || DEFAULT_TENANT_ID
|
|
30
|
-
} else {
|
|
31
|
-
userTenantId = getTenantId()
|
|
32
|
-
}
|
|
33
|
-
const tenantId = getTenantIDFromAppID(appId) || DEFAULT_TENANT_ID
|
|
34
|
-
return tenantId === userTenantId
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const ALL_STRATEGIES = Object.values(TenantResolutionStrategy)
|
|
38
|
-
|
|
39
|
-
export const getTenantIDFromCtx = (
|
|
40
|
-
ctx: BBContext,
|
|
41
|
-
opts: GetTenantIdOptions
|
|
42
|
-
): string | undefined => {
|
|
43
|
-
// exit early if not multi-tenant
|
|
44
|
-
if (!isMultiTenant()) {
|
|
45
|
-
return DEFAULT_TENANT_ID
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// opt defaults
|
|
49
|
-
if (opts.allowNoTenant === undefined) {
|
|
50
|
-
opts.allowNoTenant = false
|
|
51
|
-
}
|
|
52
|
-
if (!opts.includeStrategies) {
|
|
53
|
-
opts.includeStrategies = ALL_STRATEGIES
|
|
54
|
-
}
|
|
55
|
-
if (!opts.excludeStrategies) {
|
|
56
|
-
opts.excludeStrategies = []
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const isAllowed = (strategy: TenantResolutionStrategy) => {
|
|
60
|
-
// excluded takes precedence
|
|
61
|
-
if (opts.excludeStrategies?.includes(strategy)) {
|
|
62
|
-
return false
|
|
63
|
-
}
|
|
64
|
-
if (opts.includeStrategies?.includes(strategy)) {
|
|
65
|
-
return true
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// always use user first
|
|
70
|
-
if (isAllowed(TenantResolutionStrategy.USER)) {
|
|
71
|
-
const userTenantId = ctx.user?.tenantId
|
|
72
|
-
if (userTenantId) {
|
|
73
|
-
return userTenantId
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// header
|
|
78
|
-
if (isAllowed(TenantResolutionStrategy.HEADER)) {
|
|
79
|
-
const headerTenantId = ctx.request.headers[Header.TENANT_ID]
|
|
80
|
-
if (headerTenantId) {
|
|
81
|
-
return headerTenantId as string
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// query param
|
|
86
|
-
if (isAllowed(TenantResolutionStrategy.QUERY)) {
|
|
87
|
-
const queryTenantId = ctx.request.query.tenantId
|
|
88
|
-
if (queryTenantId) {
|
|
89
|
-
return queryTenantId as string
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// subdomain
|
|
94
|
-
if (isAllowed(TenantResolutionStrategy.SUBDOMAIN)) {
|
|
95
|
-
// e.g. budibase.app or local.com:10000
|
|
96
|
-
let platformHost
|
|
97
|
-
try {
|
|
98
|
-
platformHost = new URL(getPlatformURL()).host.split(":")[0]
|
|
99
|
-
} catch (err: any) {
|
|
100
|
-
// if invalid URL, just don't try to process subdomain
|
|
101
|
-
if (err.code !== "ERR_INVALID_URL") {
|
|
102
|
-
throw err
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
// e.g. tenant.budibase.app or tenant.local.com
|
|
106
|
-
const requestHost = ctx.host
|
|
107
|
-
// parse the tenant id from the difference
|
|
108
|
-
if (platformHost && requestHost.includes(platformHost)) {
|
|
109
|
-
const tenantId = requestHost.substring(
|
|
110
|
-
0,
|
|
111
|
-
requestHost.indexOf(`.${platformHost}`)
|
|
112
|
-
)
|
|
113
|
-
if (tenantId) {
|
|
114
|
-
return tenantId
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// path
|
|
120
|
-
if (isAllowed(TenantResolutionStrategy.PATH)) {
|
|
121
|
-
// params - have to parse manually due to koa-router not run yet
|
|
122
|
-
const match = ctx.matched.find(
|
|
123
|
-
(m: any) => !!m.paramNames.find((p: any) => p.name === "tenantId")
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
// get the raw path url - without any query params
|
|
127
|
-
const ctxUrl = ctx.originalUrl
|
|
128
|
-
let url
|
|
129
|
-
if (ctxUrl.includes("?")) {
|
|
130
|
-
url = ctxUrl.split("?")[0]
|
|
131
|
-
} else {
|
|
132
|
-
url = ctxUrl
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (match) {
|
|
136
|
-
const params = match.params(url, match.captures(url), {})
|
|
137
|
-
if (params.tenantId) {
|
|
138
|
-
return params.tenantId
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (!opts.allowNoTenant) {
|
|
144
|
-
ctx.throw(403, "Tenant id not set")
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return undefined
|
|
148
|
-
}
|