Fix table.spec.ts.
This commit is contained in:
parent
78bbf90f17
commit
dbe9eedcba
|
@ -3,7 +3,6 @@ import * as dbCore from "../db"
|
||||||
import {
|
import {
|
||||||
getNativeSql,
|
getNativeSql,
|
||||||
isExternalTable,
|
isExternalTable,
|
||||||
isInternalTableID,
|
|
||||||
isInvalidISODateString,
|
isInvalidISODateString,
|
||||||
isValidFilter,
|
isValidFilter,
|
||||||
isValidISODateString,
|
isValidISODateString,
|
||||||
|
@ -497,9 +496,8 @@ class InternalBuilder {
|
||||||
filterKey: string,
|
filterKey: string,
|
||||||
whereCb: (filterKey: string, query: Knex.QueryBuilder) => Knex.QueryBuilder
|
whereCb: (filterKey: string, query: Knex.QueryBuilder) => Knex.QueryBuilder
|
||||||
): Knex.QueryBuilder {
|
): Knex.QueryBuilder {
|
||||||
const { relationships, endpoint, tableAliases: aliases } = this.query
|
const { relationships, endpoint, tableAliases: aliases, table } = this.query
|
||||||
const tableName = endpoint.entityId
|
const fromAlias = aliases?.[table.name] || table.name
|
||||||
const fromAlias = aliases?.[tableName] || tableName
|
|
||||||
const matches = (value: string) =>
|
const matches = (value: string) =>
|
||||||
filterKey.match(new RegExp(`^${value}\\.`))
|
filterKey.match(new RegExp(`^${value}\\.`))
|
||||||
if (!relationships) {
|
if (!relationships) {
|
||||||
|
@ -1455,14 +1453,14 @@ class InternalBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
qualifiedKnex(opts?: { alias?: string | boolean }): Knex.QueryBuilder {
|
qualifiedKnex(opts?: { alias?: string | boolean }): Knex.QueryBuilder {
|
||||||
let alias = this.query.tableAliases?.[this.query.endpoint.entityId]
|
let alias = this.query.tableAliases?.[this.query.table.name]
|
||||||
if (opts?.alias === false) {
|
if (opts?.alias === false) {
|
||||||
alias = undefined
|
alias = undefined
|
||||||
} else if (typeof opts?.alias === "string") {
|
} else if (typeof opts?.alias === "string") {
|
||||||
alias = opts.alias
|
alias = opts.alias
|
||||||
}
|
}
|
||||||
return this.knex(
|
return this.knex(
|
||||||
this.tableNameWithSchema(this.query.endpoint.entityId, {
|
this.tableNameWithSchema(this.query.table.name, {
|
||||||
alias,
|
alias,
|
||||||
schema: this.query.endpoint.schema,
|
schema: this.query.endpoint.schema,
|
||||||
})
|
})
|
||||||
|
@ -1558,11 +1556,10 @@ class InternalBuilder {
|
||||||
limits?: { base: number; query: number }
|
limits?: { base: number; query: number }
|
||||||
} = {}
|
} = {}
|
||||||
): Knex.QueryBuilder {
|
): Knex.QueryBuilder {
|
||||||
let { endpoint, filters, paginate, relationships } = this.query
|
let { endpoint, filters, paginate, relationships, table } = this.query
|
||||||
const { limits } = opts
|
const { limits } = opts
|
||||||
const counting = endpoint.operation === Operation.COUNT
|
const counting = endpoint.operation === Operation.COUNT
|
||||||
|
|
||||||
const tableName = endpoint.entityId
|
|
||||||
// start building the query
|
// start building the query
|
||||||
let query = this.qualifiedKnex()
|
let query = this.qualifiedKnex()
|
||||||
// handle pagination
|
// handle pagination
|
||||||
|
@ -1610,9 +1607,7 @@ class InternalBuilder {
|
||||||
|
|
||||||
// handle relationships with a CTE for all others
|
// handle relationships with a CTE for all others
|
||||||
if (relationships?.length && aggregations.length === 0) {
|
if (relationships?.length && aggregations.length === 0) {
|
||||||
const mainTable =
|
const mainTable = this.query.tableAliases?.[table.name] || table.name
|
||||||
this.query.tableAliases?.[this.query.endpoint.entityId] ||
|
|
||||||
this.query.endpoint.entityId
|
|
||||||
const cte = this.addSorting(
|
const cte = this.addSorting(
|
||||||
this.knex
|
this.knex
|
||||||
.with("paginated", query)
|
.with("paginated", query)
|
||||||
|
@ -1622,7 +1617,7 @@ class InternalBuilder {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
// add JSON aggregations attached to the CTE
|
// add JSON aggregations attached to the CTE
|
||||||
return this.addJsonRelationships(cte, tableName, relationships)
|
return this.addJsonRelationships(cte, table.name, relationships)
|
||||||
}
|
}
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
|
@ -25,7 +25,7 @@ function generateSchema(
|
||||||
schema: CreateTableBuilder,
|
schema: CreateTableBuilder,
|
||||||
table: Table,
|
table: Table,
|
||||||
tables: Record<string, Table>,
|
tables: Record<string, Table>,
|
||||||
oldTable: null | Table = null,
|
oldTable?: Table,
|
||||||
renamed?: RenameColumn
|
renamed?: RenameColumn
|
||||||
) {
|
) {
|
||||||
let primaryKeys = table && table.primary ? table.primary : []
|
let primaryKeys = table && table.primary ? table.primary : []
|
||||||
|
@ -55,7 +55,7 @@ function generateSchema(
|
||||||
)
|
)
|
||||||
for (let [key, column] of Object.entries(table.schema)) {
|
for (let [key, column] of Object.entries(table.schema)) {
|
||||||
// skip things that are already correct
|
// skip things that are already correct
|
||||||
const oldColumn = oldTable ? oldTable.schema[key] : null
|
const oldColumn = oldTable?.schema[key]
|
||||||
if (
|
if (
|
||||||
(oldColumn && oldColumn.type) ||
|
(oldColumn && oldColumn.type) ||
|
||||||
columnTypeSet.includes(key) ||
|
columnTypeSet.includes(key) ||
|
||||||
|
@ -199,7 +199,7 @@ function buildUpdateTable(
|
||||||
knex: SchemaBuilder,
|
knex: SchemaBuilder,
|
||||||
table: Table,
|
table: Table,
|
||||||
tables: Record<string, Table>,
|
tables: Record<string, Table>,
|
||||||
oldTable: Table,
|
oldTable?: Table,
|
||||||
renamed?: RenameColumn
|
renamed?: RenameColumn
|
||||||
): SchemaBuilder {
|
): SchemaBuilder {
|
||||||
return knex.alterTable(table.name, schema => {
|
return knex.alterTable(table.name, schema => {
|
||||||
|
@ -281,7 +281,7 @@ class SqlTableQueryBuilder {
|
||||||
client,
|
client,
|
||||||
json.table,
|
json.table,
|
||||||
json.tables,
|
json.tables,
|
||||||
json.table,
|
json.meta?.oldTable,
|
||||||
json.meta?.renamed
|
json.meta?.renamed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 06e4506cef37110e509a0ef0b9811ac07f8b2844
|
Subproject commit 8c5125b4f6e53d0a43d4de90aecbf53d9f7da8ff
|
|
@ -137,7 +137,7 @@ function cleanupConfig(config: RunConfig, table: Table): RunConfig {
|
||||||
|
|
||||||
function getEndpoint(tableId: string, operation: Operation) {
|
function getEndpoint(tableId: string, operation: Operation) {
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
return { datasource: datasourceId, entityId: tableName, operation }
|
return { datasourceId, entityId: tableName, operation }
|
||||||
}
|
}
|
||||||
|
|
||||||
function isOneSide(
|
function isOneSide(
|
||||||
|
@ -706,8 +706,8 @@ export class ExternalRequest<T extends Operation> {
|
||||||
|
|
||||||
let json: QueryJson = {
|
let json: QueryJson = {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
datasource: this.datasource,
|
datasourceId: this.datasource,
|
||||||
entityId: table.name,
|
entityId: table,
|
||||||
operation,
|
operation,
|
||||||
},
|
},
|
||||||
resource: {
|
resource: {
|
||||||
|
|
|
@ -11,19 +11,23 @@ export async function makeTableRequest(
|
||||||
datasource: Datasource,
|
datasource: Datasource,
|
||||||
operation: Operation,
|
operation: Operation,
|
||||||
table: Table,
|
table: Table,
|
||||||
|
oldTable?: Table,
|
||||||
renamed?: RenameColumn
|
renamed?: RenameColumn
|
||||||
) {
|
) {
|
||||||
const json: QueryJson = {
|
const json: QueryJson = {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
datasource,
|
datasourceId: datasource,
|
||||||
entityId: table._id!,
|
entityId: table,
|
||||||
operation,
|
operation,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if (!json.meta) {
|
||||||
|
json.meta = {}
|
||||||
|
}
|
||||||
|
if (oldTable) {
|
||||||
|
json.meta.oldTable = oldTable
|
||||||
|
}
|
||||||
if (renamed) {
|
if (renamed) {
|
||||||
if (!json.meta) {
|
|
||||||
json.meta = {}
|
|
||||||
}
|
|
||||||
json.meta.renamed = renamed
|
json.meta.renamed = renamed
|
||||||
}
|
}
|
||||||
return makeExternalQuery(json)
|
return makeExternalQuery(json)
|
||||||
|
|
|
@ -54,7 +54,7 @@ export async function updateTable(
|
||||||
return table
|
return table
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
ctx.throw(400, err.message)
|
throw err
|
||||||
} else {
|
} else {
|
||||||
ctx.throw(err.status || 500, err?.message || err)
|
ctx.throw(err.status || 500, err?.message || err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -837,7 +837,7 @@ if (descriptions.length) {
|
||||||
|
|
||||||
const res = await config.api.datasource.query({
|
const res = await config.api.datasource.query({
|
||||||
endpoint: {
|
endpoint: {
|
||||||
datasource: datasource._id!,
|
datasourceId: datasource._id!,
|
||||||
operation: Operation.READ,
|
operation: Operation.READ,
|
||||||
entityId,
|
entityId,
|
||||||
},
|
},
|
||||||
|
|
|
@ -382,7 +382,7 @@ export class GoogleSheetsIntegration implements DatasourcePlus {
|
||||||
}
|
}
|
||||||
|
|
||||||
async query(json: EnrichedQueryJson): Promise<DatasourcePlusQueryResponse> {
|
async query(json: EnrichedQueryJson): Promise<DatasourcePlusQueryResponse> {
|
||||||
const sheet = json.endpoint.entityId
|
const sheet = json.table.name
|
||||||
switch (json.endpoint.operation) {
|
switch (json.endpoint.operation) {
|
||||||
case Operation.CREATE:
|
case Operation.CREATE:
|
||||||
return this.create({ sheet, row: json.body as Row })
|
return this.create({ sheet, row: json.body as Row })
|
||||||
|
|
|
@ -580,7 +580,7 @@ class OracleIntegration extends Sql implements DatasourcePlus {
|
||||||
operation !== Operation.DELETE
|
operation !== Operation.DELETE
|
||||||
) {
|
) {
|
||||||
const lastRow = await this.internalQuery({
|
const lastRow = await this.internalQuery({
|
||||||
sql: `SELECT * FROM "${json.endpoint.entityId}" WHERE ROWID = '${response.lastRowid}'`,
|
sql: `SELECT * FROM "${json.table.name}" WHERE ROWID = '${response.lastRowid}'`,
|
||||||
})
|
})
|
||||||
return lastRow.rows as Row[]
|
return lastRow.rows as Row[]
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -231,8 +231,7 @@ describe("Captures of real examples", () => {
|
||||||
}, queryJson)
|
}, queryJson)
|
||||||
expect(returningQuery).toEqual({
|
expect(returningQuery).toEqual({
|
||||||
sql: multiline(
|
sql: multiline(
|
||||||
`select top (@p0) * from [people] as [a] where CASE WHEN [a].[name] = @p1 THEN 1 ELSE 0 END = 1 and
|
`select top (@p0) * from [people] where CASE WHEN [people].[name] = @p1 THEN 1 ELSE 0 END = 1 and CASE WHEN [people].[age] = @p2 THEN 1 ELSE 0 END = 1 order by [people].[name] asc`
|
||||||
CASE WHEN [a].[age] = @p2 THEN 1 ELSE 0 END = 1 order by [a].[name] asc`
|
|
||||||
),
|
),
|
||||||
bindings: [1, "Test", 22],
|
bindings: [1, "Test", 22],
|
||||||
})
|
})
|
||||||
|
@ -270,7 +269,7 @@ describe("Captures of real examples", () => {
|
||||||
fields: string[] = ["a"]
|
fields: string[] = ["a"]
|
||||||
): EnrichedQueryJson {
|
): EnrichedQueryJson {
|
||||||
return {
|
return {
|
||||||
endpoint: { datasource: "", entityId: "", operation: op },
|
endpoint: { datasourceId: "", entityId: "", operation: op },
|
||||||
resource: {
|
resource: {
|
||||||
fields,
|
fields,
|
||||||
},
|
},
|
||||||
|
|
|
@ -358,7 +358,7 @@ export async function search(
|
||||||
const request: QueryJson = {
|
const request: QueryJson = {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
// not important, we query ourselves
|
// not important, we query ourselves
|
||||||
datasource: SQS_DATASOURCE_INTERNAL,
|
datasourceId: SQS_DATASOURCE_INTERNAL,
|
||||||
entityId: table._id!,
|
entityId: table._id!,
|
||||||
operation: Operation.READ,
|
operation: Operation.READ,
|
||||||
},
|
},
|
||||||
|
|
|
@ -222,7 +222,7 @@ export default class AliasTables {
|
||||||
aliases: this.aliasMap([
|
aliases: this.aliasMap([
|
||||||
relationship.through,
|
relationship.through,
|
||||||
relationship.tableName,
|
relationship.tableName,
|
||||||
json.endpoint.entityId,
|
json.table.name,
|
||||||
]),
|
]),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,6 @@ import { isSQL } from "../../../integrations/utils"
|
||||||
import { docIds, sql, SQS_DATASOURCE_INTERNAL } from "@budibase/backend-core"
|
import { docIds, sql, SQS_DATASOURCE_INTERNAL } from "@budibase/backend-core"
|
||||||
import { getTableFromSource } from "../../../api/controllers/row/utils"
|
import { getTableFromSource } from "../../../api/controllers/row/utils"
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
import { breakExternalTableId } from "@budibase/backend-core/src/sql/utils"
|
|
||||||
import { isDatasourceId } from "@budibase/backend-core/src/docIds"
|
|
||||||
|
|
||||||
const SQL_CLIENT_SOURCE_MAP: Record<SourceName, SqlClient | undefined> = {
|
const SQL_CLIENT_SOURCE_MAP: Record<SourceName, SqlClient | undefined> = {
|
||||||
[SourceName.POSTGRES]: SqlClient.POSTGRES,
|
[SourceName.POSTGRES]: SqlClient.POSTGRES,
|
||||||
|
@ -90,18 +88,15 @@ export async function enrichQueryJson(
|
||||||
json: QueryJson
|
json: QueryJson
|
||||||
): Promise<EnrichedQueryJson> {
|
): Promise<EnrichedQueryJson> {
|
||||||
let datasource: Datasource | undefined = undefined
|
let datasource: Datasource | undefined = undefined
|
||||||
let entityId = json.endpoint.entityId
|
|
||||||
if (typeof json.endpoint.datasource === "string") {
|
if (typeof json.endpoint.datasourceId === "string") {
|
||||||
if (json.endpoint.datasource !== SQS_DATASOURCE_INTERNAL) {
|
if (json.endpoint.datasourceId !== SQS_DATASOURCE_INTERNAL) {
|
||||||
datasource = await sdk.datasources.get(json.endpoint.datasource, {
|
datasource = await sdk.datasources.get(json.endpoint.datasourceId, {
|
||||||
enriched: true,
|
enriched: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
datasource = json.endpoint.datasource
|
datasource = json.endpoint.datasourceId
|
||||||
if (isDatasourceId(entityId)) {
|
|
||||||
entityId = breakExternalTableId(entityId).tableName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let tables: Record<string, Table>
|
let tables: Record<string, Table>
|
||||||
|
@ -111,7 +106,16 @@ export async function enrichQueryJson(
|
||||||
tables = processInternalTables(await sdk.tables.getAllInternalTables())
|
tables = processInternalTables(await sdk.tables.getAllInternalTables())
|
||||||
}
|
}
|
||||||
|
|
||||||
const table = tables[entityId]
|
let table: Table
|
||||||
|
if (typeof json.endpoint.entityId === "string") {
|
||||||
|
let entityId = json.endpoint.entityId
|
||||||
|
if (docIds.isDatasourceId(entityId)) {
|
||||||
|
entityId = sql.utils.breakExternalTableId(entityId).tableName
|
||||||
|
}
|
||||||
|
table = tables[entityId]
|
||||||
|
} else {
|
||||||
|
table = json.endpoint.entityId
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
table,
|
table,
|
||||||
|
|
|
@ -241,7 +241,13 @@ export async function save(
|
||||||
}
|
}
|
||||||
|
|
||||||
const operation = tableId ? Operation.UPDATE_TABLE : Operation.CREATE_TABLE
|
const operation = tableId ? Operation.UPDATE_TABLE : Operation.CREATE_TABLE
|
||||||
await makeTableRequest(datasource, operation, tableToSave, opts?.renaming)
|
await makeTableRequest(
|
||||||
|
datasource,
|
||||||
|
operation,
|
||||||
|
tableToSave,
|
||||||
|
oldTable,
|
||||||
|
opts?.renaming
|
||||||
|
)
|
||||||
// update any extra tables (like foreign keys in other tables)
|
// update any extra tables (like foreign keys in other tables)
|
||||||
for (let extraTable of extraTablesToUpdate) {
|
for (let extraTable of extraTablesToUpdate) {
|
||||||
const oldExtraTable = oldTables[extraTable.name]
|
const oldExtraTable = oldTables[extraTable.name]
|
||||||
|
|
|
@ -158,8 +158,8 @@ export interface ManyToManyRelationshipJson {
|
||||||
|
|
||||||
export interface QueryJson {
|
export interface QueryJson {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
datasource: string | Datasource
|
datasourceId: string | Datasource
|
||||||
entityId: string
|
entityId: string | Table
|
||||||
operation: Operation
|
operation: Operation
|
||||||
schema?: string
|
schema?: string
|
||||||
}
|
}
|
||||||
|
@ -173,6 +173,7 @@ export interface QueryJson {
|
||||||
body?: Row | Row[]
|
body?: Row | Row[]
|
||||||
meta?: {
|
meta?: {
|
||||||
renamed?: RenameColumn
|
renamed?: RenameColumn
|
||||||
|
oldTable?: Table
|
||||||
// can specify something that columns could be prefixed with
|
// can specify something that columns could be prefixed with
|
||||||
columnPrefix?: string
|
columnPrefix?: string
|
||||||
}
|
}
|
||||||
|
@ -190,7 +191,7 @@ export interface EnrichedQueryJson extends QueryJson {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryJsonRequest extends Omit<QueryJson, "endpoint"> {
|
export interface QueryJsonRequest extends Omit<QueryJson, "endpoint"> {
|
||||||
endpoint: QueryJson["endpoint"] & { datasource: string }
|
endpoint: QueryJson["endpoint"] & { datasourceId: string; entityId: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryOptions {
|
export interface QueryOptions {
|
||||||
|
|
Loading…
Reference in New Issue