1
0
Fork 0
mirror of synced 2024-07-07 15:25:52 +12:00

Disabling aliasing on writes (create, update, delete) for MySQL/MS-SQL datasources.

This commit is contained in:
Michael Drury 2024-03-05 16:19:21 +00:00
parent bc8fdeea6a
commit a332c058ce
4 changed files with 74 additions and 15 deletions

View file

@ -1,12 +1,16 @@
import { import {
QueryJson, Datasource,
SearchFilters,
Table,
Row,
DatasourcePlusQueryResponse, DatasourcePlusQueryResponse,
Operation,
QueryJson,
Row,
SearchFilters,
} from "@budibase/types" } from "@budibase/types"
import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils" import { getSQLClient } from "../../../sdk/app/rows/utils"
import { cloneDeep } from "lodash" import { cloneDeep } from "lodash"
import sdk from "../../../sdk"
import { makeExternalQuery } from "../../../integrations/base/query"
import { SqlClient } from "../../../integrations/utils"
class CharSequence { class CharSequence {
static alphabet = "abcdefghijklmnopqrstuvwxyz" static alphabet = "abcdefghijklmnopqrstuvwxyz"
@ -43,6 +47,32 @@ export default class AliasTables {
this.charSeq = new CharSequence() this.charSeq = new CharSequence()
} }
isAliasingEnabled(json: QueryJson, datasource: Datasource) {
const fieldLength = json.resource?.fields?.length
if (!fieldLength || fieldLength <= 0) {
return false
}
const writeOperations = [
Operation.CREATE,
Operation.UPDATE,
Operation.DELETE,
]
try {
const sqlClient = getSQLClient(datasource)
const isWrite = writeOperations.includes(json.endpoint.operation)
if (
isWrite &&
(sqlClient === SqlClient.MY_SQL || sqlClient === SqlClient.MS_SQL)
) {
return false
}
} catch (err) {
// if we can't get an SQL client, we can't alias
return false
}
return true
}
getAlias(tableName: string) { getAlias(tableName: string) {
if (this.aliases[tableName]) { if (this.aliases[tableName]) {
return this.aliases[tableName] return this.aliases[tableName]
@ -111,8 +141,10 @@ export default class AliasTables {
} }
async queryWithAliasing(json: QueryJson): DatasourcePlusQueryResponse { async queryWithAliasing(json: QueryJson): DatasourcePlusQueryResponse {
const fieldLength = json.resource?.fields?.length const datasourceId = json.endpoint.datasourceId
const aliasingEnabled = fieldLength && fieldLength > 0 const datasource = await sdk.datasources.get(datasourceId)
const aliasingEnabled = this.isAliasingEnabled(json, datasource)
if (aliasingEnabled) { if (aliasingEnabled) {
json = cloneDeep(json) json = cloneDeep(json)
// run through the query json to update anywhere a table may be used // run through the query json to update anywhere a table may be used
@ -158,7 +190,7 @@ export default class AliasTables {
} }
json.tableAliases = invertedTableAliases json.tableAliases = invertedTableAliases
} }
const response = await getDatasourceAndQuery(json) const response = await makeExternalQuery(datasource, json)
if (Array.isArray(response) && aliasingEnabled) { if (Array.isArray(response) && aliasingEnabled) {
return this.reverse(response) return this.reverse(response)
} else { } else {

View file

@ -435,10 +435,12 @@ class InternalBuilder {
aliases?: QueryJson["tableAliases"] aliases?: QueryJson["tableAliases"]
): Knex.QueryBuilder { ): Knex.QueryBuilder {
const tableName = endpoint.entityId const tableName = endpoint.entityId
const tableAliased = aliases?.[tableName] const tableAlias = aliases?.[tableName]
? `${tableName} as ${aliases?.[tableName]}` let table: string | Record<string, string> = tableName
: tableName if (tableAlias) {
let query = knex(tableAliased) table = { [tableAlias]: tableName }
}
let query = knex(table)
if (endpoint.schema) { if (endpoint.schema) {
query = query.withSchema(endpoint.schema) query = query.withSchema(endpoint.schema)
} }

View file

@ -14,13 +14,18 @@ import firebase from "./firebase"
import redis from "./redis" import redis from "./redis"
import snowflake from "./snowflake" import snowflake from "./snowflake"
import oracle from "./oracle" import oracle from "./oracle"
import { SourceName, Integration, PluginType } from "@budibase/types" import {
SourceName,
Integration,
PluginType,
IntegrationBase,
} from "@budibase/types"
import { getDatasourcePlugin } from "../utilities/fileSystem" import { getDatasourcePlugin } from "../utilities/fileSystem"
import env from "../environment" import env from "../environment"
import cloneDeep from "lodash/cloneDeep" import cloneDeep from "lodash/cloneDeep"
import sdk from "../sdk" import sdk from "../sdk"
const DEFINITIONS: Record<SourceName, Integration | undefined> = { const DEFINITIONS: { [key: SourceName]: Integration | undefined } = {
[SourceName.POSTGRES]: postgres.schema, [SourceName.POSTGRES]: postgres.schema,
[SourceName.DYNAMODB]: dynamodb.schema, [SourceName.DYNAMODB]: dynamodb.schema,
[SourceName.MONGODB]: mongodb.schema, [SourceName.MONGODB]: mongodb.schema,
@ -40,7 +45,7 @@ const DEFINITIONS: Record<SourceName, Integration | undefined> = {
[SourceName.BUDIBASE]: undefined, [SourceName.BUDIBASE]: undefined,
} }
const INTEGRATIONS: Record<SourceName, any> = { const INTEGRATIONS: { [key: SourceName]: IntegrationBase | undefined } = {
[SourceName.POSTGRES]: postgres.integration, [SourceName.POSTGRES]: postgres.integration,
[SourceName.DYNAMODB]: dynamodb.integration, [SourceName.DYNAMODB]: dynamodb.integration,
[SourceName.MONGODB]: mongodb.integration, [SourceName.MONGODB]: mongodb.integration,

View file

@ -7,11 +7,31 @@ import {
Table, Table,
TableSchema, TableSchema,
DatasourcePlusQueryResponse, DatasourcePlusQueryResponse,
Datasource,
SourceName,
} from "@budibase/types" } from "@budibase/types"
import { makeExternalQuery } from "../../../integrations/base/query" import { makeExternalQuery } from "../../../integrations/base/query"
import { Format } from "../../../api/controllers/view/exporters" import { Format } from "../../../api/controllers/view/exporters"
import sdk from "../.." import sdk from "../.."
import { isRelationshipColumn } from "../../../db/utils" import { isRelationshipColumn } from "../../../db/utils"
import { SqlClient } from "../../../integrations/utils"
export function getSQLClient(datasource: Datasource): SqlClient {
if (!datasource.isSQL) {
throw new Error("Cannot get SQL Client for non-SQL datasource")
}
switch (datasource.source) {
case SourceName.POSTGRES:
return SqlClient.POSTGRES
case SourceName.MYSQL:
return SqlClient.MY_SQL
case SourceName.ORACLE:
return SqlClient.ORACLE
case SourceName.SQL_SERVER:
return SqlClient.MS_SQL
}
throw new Error("Unable to find a valid SQL client")
}
export async function getDatasourceAndQuery( export async function getDatasourceAndQuery(
json: QueryJson json: QueryJson