From 8765a28f0412aa3cb5353c23d655c34ab0116864 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 17 Dec 2024 13:02:34 +0100 Subject: [PATCH] Move responsability to sql utils --- packages/backend-core/src/sql/sql.ts | 21 ------- .../src/api/controllers/row/utils/sqlUtils.ts | 63 +++++++++---------- .../src/integrations/tests/sqlAlias.spec.ts | 17 ----- 3 files changed, 31 insertions(+), 70 deletions(-) diff --git a/packages/backend-core/src/sql/sql.ts b/packages/backend-core/src/sql/sql.ts index 015b7c4751..cc5f226d56 100644 --- a/packages/backend-core/src/sql/sql.ts +++ b/packages/backend-core/src/sql/sql.ts @@ -272,20 +272,6 @@ class InternalBuilder { return parts.join(".") } - private isFullSelectStatementRequired(includedFields: string[]): boolean { - for (const column of Object.values(this.table.schema)) { - if (this.SPECIAL_SELECT_CASES.MSSQL_DATES(column)) { - return true - } else if ( - column.type === FieldType.FORMULA && - includedFields.includes(column.name) - ) { - return true - } - } - return false - } - private generateSelectStatement(): (string | Knex.Raw)[] | "*" { const { table, resource } = this.query @@ -313,13 +299,6 @@ class InternalBuilder { }) .filter(({ table }) => !table || table === alias) - const requestedTableColumns = tableFields.map(({ column }) => - column.replace(new RegExp(`^${this.query.meta?.columnPrefix}`), "") - ) - if (this.isFullSelectStatementRequired(requestedTableColumns)) { - return [this.knex.raw("??", [`${alias}.*`])] - } - return tableFields.map(({ table, column, field }) => { const columnSchema = schema[column] diff --git a/packages/server/src/api/controllers/row/utils/sqlUtils.ts b/packages/server/src/api/controllers/row/utils/sqlUtils.ts index ce611b502b..750b53861f 100644 --- a/packages/server/src/api/controllers/row/utils/sqlUtils.ts +++ b/packages/server/src/api/controllers/row/utils/sqlUtils.ts @@ -14,7 +14,7 @@ import { import { breakExternalTableId } from "../../../../integrations/utils" import { generateJunctionTableID } from "../../../../db/utils" import sdk from "../../../../sdk" -import { helpers } from "@budibase/shared-core" +import { helpers, PROTECTED_INTERNAL_COLUMNS } from "@budibase/shared-core" import { sql } from "@budibase/backend-core" type TableMap = Record @@ -126,11 +126,9 @@ export async function buildSqlFieldList( column.type !== FieldType.LINK && column.type !== FieldType.FORMULA && column.type !== FieldType.AI && - !existing.find( - (field: string) => field === `${table.name}.${columnName}` - ) + !existing.find((field: string) => field === columnName) ) - .map(([columnName]) => `${table.name}.${columnName}`) + .map(([columnName]) => columnName) } function getRequiredFields(table: Table, existing: string[] = []) { @@ -143,15 +141,12 @@ export async function buildSqlFieldList( } if (!sql.utils.isExternalTable(table)) { - requiredFields.push(...["_id", "_rev", "_tableId"]) + requiredFields.push(...PROTECTED_INTERNAL_COLUMNS) } - return requiredFields - .filter( - column => - !existing.find((field: string) => field === `${table.name}.${column}`) - ) - .map(column => `${table.name}.${column}`) + return requiredFields.filter( + column => !existing.find((field: string) => field === column) + ) } let fields: string[] = [] @@ -161,30 +156,34 @@ export async function buildSqlFieldList( let table: Table if (isView) { table = await sdk.views.getTable(source.id) + + fields = Object.keys(helpers.views.basicFields(source)).filter( + f => table.schema[f].type !== FieldType.LINK + ) } else { table = source - } - - if (isView) { - fields = Object.keys(helpers.views.basicFields(source)) - .filter(f => table.schema[f].type !== FieldType.LINK) - .map(c => `${table.name}.${c}`) - - if (!helpers.views.isCalculationView(source)) { - fields.push( - ...getRequiredFields( - { - ...table, - primaryDisplay: source.primaryDisplay || table.primaryDisplay, - }, - fields - ) - ) - } - } else { fields = extractRealFields(source) } + // If are requesting for a formula field, we need to retrieve all fields + if (fields.find(f => table.schema[f]?.type === FieldType.FORMULA)) { + fields = extractRealFields(table) + } + + if (!isView || !helpers.views.isCalculationView(source)) { + fields.push( + ...getRequiredFields( + { + ...table, + primaryDisplay: source.primaryDisplay || table.primaryDisplay, + }, + fields + ) + ) + } + + fields = fields.map(c => `${table.name}.${c}`) + for (const field of Object.values(table.schema)) { if (field.type !== FieldType.LINK || !relationships || !field.tableId) { continue @@ -227,7 +226,7 @@ export async function buildSqlFieldList( } } - return fields + return [...new Set(fields)] } export function isKnexEmptyReadResponse(resp: DatasourcePlusQueryResponse) { diff --git a/packages/server/src/integrations/tests/sqlAlias.spec.ts b/packages/server/src/integrations/tests/sqlAlias.spec.ts index 647c18d4ae..898ab9314a 100644 --- a/packages/server/src/integrations/tests/sqlAlias.spec.ts +++ b/packages/server/src/integrations/tests/sqlAlias.spec.ts @@ -8,7 +8,6 @@ import { TableSchema, Table, TableSourceType, - FieldType, } from "@budibase/types" import { sql } from "@budibase/backend-core" import { join } from "path" @@ -95,22 +94,6 @@ describe("Captures of real examples", () => { }) }) - it("should retrieve all fields if a formula column is requested", () => { - const queryJson = getJson("basicFetch.json") - queryJson.table.schema["formula"] = { - name: "formula", - type: FieldType.FORMULA, - formula: "any", - } - queryJson.resource!.fields.push("formula") - - let query = new Sql(SqlClient.POSTGRES)._query(queryJson) - expect(query).toEqual({ - bindings: [primaryLimit], - sql: `select "a".* from "persons" as "a" order by "a"."firstname" asc nulls first, "a"."personid" asc limit $1`, - }) - }) - it("should handle basic retrieval with relationships", () => { const queryJson = getJson("basicFetchWithRelationships.json") let query = new Sql(SqlClient.POSTGRES, relationshipLimit)._query(