diff --git a/packages/backend-core/src/sql/sqlTable.ts b/packages/backend-core/src/sql/sqlTable.ts index 02acc8af85..55a6bfcaeb 100644 --- a/packages/backend-core/src/sql/sqlTable.ts +++ b/packages/backend-core/src/sql/sqlTable.ts @@ -28,16 +28,25 @@ function generateSchema( oldTable: null | Table = null, renamed?: RenameColumn ) { - let primaryKey = table && table.primary ? table.primary[0] : null + let primaryKeys = table && table.primary ? table.primary : [] const columns = Object.values(table.schema) // all columns in a junction table will be meta let metaCols = columns.filter(col => (col as NumberFieldMetadata).meta) let isJunction = metaCols.length === columns.length + let columnTypeSet: string[] = [] + // can't change primary once its set for now - if (primaryKey && !oldTable && !isJunction) { - schema.increments(primaryKey).primary() - } else if (!oldTable && isJunction) { - schema.primary(metaCols.map(col => col.name)) + if (!oldTable) { + // junction tables are special - we have an expected format + if (isJunction) { + schema.primary(metaCols.map(col => col.name)) + } else if (primaryKeys.length === 1) { + schema.increments(primaryKeys[0]).primary() + // note that we've set its type + columnTypeSet.push(primaryKeys[0]) + } else { + schema.primary(primaryKeys) + } } // check if any columns need added @@ -49,7 +58,7 @@ function generateSchema( const oldColumn = oldTable ? oldTable.schema[key] : null if ( (oldColumn && oldColumn.type) || - (primaryKey === key && !isJunction) || + columnTypeSet.includes(key) || renamed?.updated === key ) { continue diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 6538e7347a..14dd909edd 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -1,5 +1,6 @@ import dayjs from "dayjs" import { + ArrayOperator, AutoFieldSubType, AutoReason, Datasource, @@ -196,11 +197,12 @@ export class ExternalRequest { // need to map over the filters and make sure the _id field isn't present let prefix = 1 for (const operator of Object.values(filters)) { + const isArrayOperator = Object.values(ArrayOperator).includes(operator) for (const field of Object.keys(operator || {})) { if (dbCore.removeKeyNumbering(field) === "_id") { if (primary) { const parts = breakRowIdField(operator[field]) - if (primary.length > 1) { + if (primary.length > 1 && isArrayOperator) { operator[InternalSearchFilterOperator.COMPLEX_ID_OPERATOR] = { id: primary, values: parts[0], diff --git a/packages/server/src/api/routes/tests/search.spec.ts b/packages/server/src/api/routes/tests/search.spec.ts index 6967f7bd6e..d0cc8848ae 100644 --- a/packages/server/src/api/routes/tests/search.spec.ts +++ b/packages/server/src/api/routes/tests/search.spec.ts @@ -39,6 +39,7 @@ import { dataFilters } from "@budibase/shared-core" import { Knex } from "knex" import { structures } from "@budibase/backend-core/tests" import { DEFAULT_EMPLOYEE_TABLE_SCHEMA } from "../../../db/defaultData/datasource_bb_default" +import { generateRowIdField } from "../../../integrations/utils" describe.each([ ["in-memory", undefined], @@ -2648,6 +2649,42 @@ describe.each([ }) }) + !isInternal && + describe("search by composite key", () => { + beforeAll(async () => { + table = await config.api.table.save( + tableForDatasource(datasource, { + schema: { + idColumn1: { + name: "idColumn1", + type: FieldType.NUMBER, + }, + idColumn2: { + name: "idColumn2", + type: FieldType.NUMBER, + }, + }, + primary: ["idColumn1", "idColumn2"], + }) + ) + await createRows([{ idColumn1: 1, idColumn2: 2 }]) + }) + + it("can filter by the row ID with limit 1", async () => { + await expectSearch({ + query: { + equal: { _id: generateRowIdField([1, 2]) }, + }, + limit: 1, + }).toContain([ + { + idColumn1: 1, + idColumn2: 2, + }, + ]) + }) + }) + isSql && describe("pagination edge case with relationships", () => { let mainRows: Row[] = [] diff --git a/packages/server/src/utilities/schema.ts b/packages/server/src/utilities/schema.ts index b398285710..b1fbd7577a 100644 --- a/packages/server/src/utilities/schema.ts +++ b/packages/server/src/utilities/schema.ts @@ -146,7 +146,8 @@ export function parse(rows: Rows, table: Table): Rows { return rows.map(row => { const parsedRow: Row = {} - Object.entries(row).forEach(([columnName, columnData]) => { + Object.keys(row).forEach(columnName => { + const columnData = row[columnName] const schema = table.schema if (!(columnName in schema)) { // Objects can be present in the row data but not in the schema, so make sure we don't proceed in such a case