Fixing an issue with relationship modal breaking when multiple data sources available to relate to, also fixing an pile of issues with creating and reading rows from SQL server plus.
This commit is contained in:
parent
3474f3ae8e
commit
b34cef26c3
|
@ -59,9 +59,6 @@
|
|||
let deletion
|
||||
|
||||
$: checkConstraints(field)
|
||||
$: tableOptions = $tables.list.filter(
|
||||
opt => opt._id !== $tables.draft._id && opt.type === table.type
|
||||
)
|
||||
$: required = !!field?.constraints?.presence || primaryDisplay
|
||||
$: uneditable =
|
||||
$tables.selected?._id === TableNames.USERS &&
|
||||
|
@ -88,6 +85,14 @@
|
|||
field.type !== LINK_TYPE && !uneditable && field.type !== AUTO_TYPE
|
||||
$: relationshipOptions = getRelationshipOptions(field)
|
||||
$: external = table.type === "external"
|
||||
// in the case of internal tables the sourceId will just be undefined
|
||||
$: tableOptions = $tables.list.filter(
|
||||
opt =>
|
||||
opt._id !== $tables.draft._id &&
|
||||
opt.type === table.type &&
|
||||
table.sourceId === opt.sourceId
|
||||
)
|
||||
$: console.log(tableOptions)
|
||||
|
||||
async function saveColumn() {
|
||||
if (field.type === AUTO_TYPE) {
|
||||
|
@ -174,7 +179,7 @@
|
|||
if (!field || !field.tableId) {
|
||||
return null
|
||||
}
|
||||
const linkTable = tableOptions.find(table => table._id === field.tableId)
|
||||
const linkTable = tableOptions?.find(table => table._id === field.tableId)
|
||||
if (!linkTable) {
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ export interface SortJson {
|
|||
|
||||
export interface PaginationJson {
|
||||
limit: number
|
||||
page: string | number
|
||||
page?: string | number
|
||||
}
|
||||
|
||||
export interface RelationshipsJson {
|
||||
|
|
|
@ -216,6 +216,10 @@ class InternalBuilder {
|
|||
query = query.orderBy(key, direction)
|
||||
}
|
||||
}
|
||||
if (this.client === "mssql" && !sort && paginate?.limit) {
|
||||
// @ts-ignore
|
||||
query = query.orderBy(json.meta?.table?.primary[0])
|
||||
}
|
||||
query = this.addFilters(tableName, query, filters)
|
||||
// @ts-ignore
|
||||
let preQuery: KnexQuery = knex({
|
||||
|
@ -301,6 +305,85 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
|
|||
// @ts-ignore
|
||||
return query.toSQL().toNative()
|
||||
}
|
||||
|
||||
async getReturningRow(queryFn: Function, json: QueryJson) {
|
||||
if (!json.extra || !json.extra.idFilter) {
|
||||
return {}
|
||||
}
|
||||
const input = this._query({
|
||||
endpoint: {
|
||||
...json.endpoint,
|
||||
operation: Operation.READ,
|
||||
},
|
||||
resource: {
|
||||
fields: [],
|
||||
},
|
||||
filters: json.extra.idFilter,
|
||||
paginate: {
|
||||
limit: 1,
|
||||
},
|
||||
meta: json.meta,
|
||||
})
|
||||
return queryFn(input, Operation.READ)
|
||||
}
|
||||
|
||||
// when creating if an ID has been inserted need to make sure
|
||||
// the id filter is enriched with it before trying to retrieve the row
|
||||
checkLookupKeys(id: any, json: QueryJson) {
|
||||
if (!id || !json.meta?.table || !json.meta.table.primary) {
|
||||
return json
|
||||
}
|
||||
const primaryKey = json.meta.table.primary?.[0]
|
||||
json.extra = {
|
||||
idFilter: {
|
||||
equal: {
|
||||
[primaryKey]: id,
|
||||
},
|
||||
},
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
||||
// this function recreates the returning functionality of postgres
|
||||
async queryWithReturning(
|
||||
json: QueryJson,
|
||||
queryFn: Function,
|
||||
processFn: Function = (result: any) => result
|
||||
) {
|
||||
const sqlClient = this.getSqlClient()
|
||||
const operation = this._operation(json)
|
||||
const input = this._query(json, { disableReturning: true })
|
||||
if (Array.isArray(input)) {
|
||||
const responses = []
|
||||
for (let query of input) {
|
||||
responses.push(await queryFn(query, operation))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
let row
|
||||
// need to manage returning, a feature mySQL can't do
|
||||
if (operation === Operation.DELETE) {
|
||||
row = processFn(await this.getReturningRow(queryFn, json))
|
||||
}
|
||||
const response = await queryFn(input, operation)
|
||||
const results = processFn(response)
|
||||
// same as delete, manage returning
|
||||
if (operation === Operation.CREATE || operation === Operation.UPDATE) {
|
||||
let id
|
||||
if (sqlClient === "mssql") {
|
||||
id = results?.[0].id
|
||||
} else if (sqlClient === "mysql") {
|
||||
id = results?.insertId
|
||||
}
|
||||
row = processFn(
|
||||
await this.getReturningRow(queryFn, this.checkLookupKeys(id, json))
|
||||
)
|
||||
}
|
||||
if (operation !== Operation.READ) {
|
||||
return row
|
||||
}
|
||||
return results.length ? results : [{ [operation.toLowerCase()]: true }]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SqlQueryBuilder
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import {
|
||||
Integration,
|
||||
DatasourceFieldTypes,
|
||||
QueryTypes,
|
||||
Integration,
|
||||
Operation,
|
||||
QueryJson,
|
||||
QueryTypes,
|
||||
SqlQuery,
|
||||
} from "../definitions/datasource"
|
||||
import { getSqlQuery } from "./utils"
|
||||
|
@ -103,15 +104,26 @@ module MSSQLModule {
|
|||
json: DatasourceFieldTypes.JSON,
|
||||
}
|
||||
|
||||
async function internalQuery(client: any, query: SqlQuery) {
|
||||
async function internalQuery(
|
||||
client: any,
|
||||
query: SqlQuery,
|
||||
operation: string | undefined = undefined
|
||||
) {
|
||||
const request = client.request()
|
||||
try {
|
||||
if (Array.isArray(query.bindings)) {
|
||||
let count = 0
|
||||
for (let binding of query.bindings) {
|
||||
client.input(`p${count++}`, binding)
|
||||
request.input(`p${count++}`, binding)
|
||||
}
|
||||
}
|
||||
return await client.query(query.sql)
|
||||
// this is a hack to get the inserted ID back,
|
||||
// no way to do this with Knex nicely
|
||||
const sql =
|
||||
operation === Operation.CREATE
|
||||
? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;`
|
||||
: query.sql
|
||||
return await request.query(sql)
|
||||
} catch (err) {
|
||||
// @ts-ignore
|
||||
throw new Error(err)
|
||||
|
@ -180,8 +192,7 @@ module MSSQLModule {
|
|||
|
||||
async connect() {
|
||||
try {
|
||||
const client = await this.pool.connect()
|
||||
this.client = client.request()
|
||||
this.client = await this.pool.connect()
|
||||
} catch (err) {
|
||||
// @ts-ignore
|
||||
throw new Error(err)
|
||||
|
@ -276,10 +287,12 @@ module MSSQLModule {
|
|||
|
||||
async query(json: QueryJson) {
|
||||
await this.connect()
|
||||
const operation = this._operation(json).toLowerCase()
|
||||
const input = this._query(json)
|
||||
const response = await internalQuery(this.client, input)
|
||||
return response.recordset ? response.recordset : [{ [operation]: true }]
|
||||
const operation = this._operation(json)
|
||||
const queryFn = (query: any, op: string) =>
|
||||
internalQuery(this.client, query, op)
|
||||
const processFn = (result: any) =>
|
||||
result.recordset ? result.recordset : [{ [operation]: true }]
|
||||
return this.queryWithReturning(json, queryFn, processFn)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -223,67 +223,12 @@ module MySQLModule {
|
|||
return results.length ? results : [{ deleted: true }]
|
||||
}
|
||||
|
||||
async getReturningRow(json: QueryJson) {
|
||||
if (!json.extra || !json.extra.idFilter) {
|
||||
return {}
|
||||
}
|
||||
const input = this._query({
|
||||
endpoint: {
|
||||
...json.endpoint,
|
||||
operation: Operation.READ,
|
||||
},
|
||||
fields: [],
|
||||
filters: json.extra.idFilter,
|
||||
paginate: {
|
||||
limit: 1,
|
||||
},
|
||||
})
|
||||
return internalQuery(this.client, input, false)
|
||||
}
|
||||
|
||||
// when creating if an ID has been inserted need to make sure
|
||||
// the id filter is enriched with it before trying to retrieve the row
|
||||
checkLookupKeys(results: any, json: QueryJson) {
|
||||
if (!results?.insertId || !json.meta?.table || !json.meta.table.primary) {
|
||||
return json
|
||||
}
|
||||
const primaryKey = json.meta.table.primary?.[0]
|
||||
json.extra = {
|
||||
idFilter: {
|
||||
equal: {
|
||||
[primaryKey]: results.insertId,
|
||||
},
|
||||
},
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
||||
async query(json: QueryJson) {
|
||||
const operation = this._operation(json)
|
||||
this.client.connect()
|
||||
const input = this._query(json, { disableReturning: true })
|
||||
if (Array.isArray(input)) {
|
||||
const responses = []
|
||||
for (let query of input) {
|
||||
responses.push(await internalQuery(this.client, query, false))
|
||||
}
|
||||
return responses
|
||||
}
|
||||
let row
|
||||
// need to manage returning, a feature mySQL can't do
|
||||
if (operation === operation.DELETE) {
|
||||
row = this.getReturningRow(json)
|
||||
}
|
||||
const results = await internalQuery(this.client, input, false)
|
||||
// same as delete, manage returning
|
||||
if (operation === Operation.CREATE || operation === Operation.UPDATE) {
|
||||
row = this.getReturningRow(this.checkLookupKeys(results, json))
|
||||
}
|
||||
const queryFn = (query: any) => internalQuery(this.client, query, false)
|
||||
const output = await this.queryWithReturning(json, queryFn)
|
||||
this.client.end()
|
||||
if (operation !== Operation.READ) {
|
||||
return row
|
||||
}
|
||||
return results.length ? results : [{ [operation.toLowerCase()]: true }]
|
||||
return output
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { SqlQuery } from "../definitions/datasource"
|
||||
import { Operation, SqlQuery } from "../definitions/datasource"
|
||||
import { Datasource, Table } from "../definitions/common"
|
||||
import { SourceNames } from "../definitions/datasource"
|
||||
const { DocumentTypes, SEPARATOR } = require("../db/utils")
|
||||
|
|
Loading…
Reference in New Issue