From 12643385db240674f2db24a3252fe5355dee0176 Mon Sep 17 00:00:00 2001 From: Wasim Thoufiq Date: Thu, 14 Dec 2023 22:43:47 +0530 Subject: [PATCH] Fix BigInt primary key routing (#20744) Co-authored-by: Pascal Jufer --- .changeset/chatty-eagles-fix.md | 5 +++ api/src/utils/apply-query.test.ts | 65 +++++++++++++++++++++++++++++-- api/src/utils/apply-query.ts | 14 ++++++- 3 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 .changeset/chatty-eagles-fix.md diff --git a/.changeset/chatty-eagles-fix.md b/.changeset/chatty-eagles-fix.md new file mode 100644 index 0000000000..53691d4195 --- /dev/null +++ b/.changeset/chatty-eagles-fix.md @@ -0,0 +1,5 @@ +--- +'@directus/api': patch +--- + +Ensured filter values higher than JavaScript max safe integer work with big integer fields diff --git a/api/src/utils/apply-query.test.ts b/api/src/utils/apply-query.test.ts index 2d83a482d8..b5dd90eb6f 100644 --- a/api/src/utils/apply-query.test.ts +++ b/api/src/utils/apply-query.test.ts @@ -76,6 +76,8 @@ const FAKE_SCHEMA: SchemaOverview = { relations: [], }; +class Client_SQLite3 extends MockClient {} + describe('applySearch', () => { function mockDatabase() { const self: Record = { @@ -158,10 +160,7 @@ describe('applyFilter', () => { for (const { filterOperator, sqlWhereClause } of withReverseOperators) { for (const filterValue of [true, '', false]) { test(`${filterOperator} with value ${filterValue}`, async () => { - class Client_SQLite3 extends MockClient {} - const db = vi.mocked(knex.default({ client: Client_SQLite3 })); - const queryBuilder = db.queryBuilder(); const collection = 'test'; @@ -190,4 +189,64 @@ describe('applyFilter', () => { } } }); + + test(`filter values on bigint fields are correctly passed as such to db query`, async () => { + const collection = 'test'; + const field = 'bigInteger'; + + const BIGINT_FAKE_SCHEMA: SchemaOverview = { + collections: { + [collection]: { + collection: 'test', + primary: 'id', + singleton: false, + sortField: null, + note: null, + accountability: null, + fields: { + [field]: { + field: field, + defaultValue: null, + nullable: false, + generated: false, + type: 'bigInteger', + dbType: null, + precision: null, + scale: null, + special: [], + note: null, + validation: null, + alias: false, + }, + }, + }, + }, + relations: [], + }; + + const db = vi.mocked(knex.default({ client: Client_SQLite3 })); + const queryBuilder = db.queryBuilder(); + + // testing with value greater than Number.MAX_SAFE_INTEGER + const bigintId = 9007199254740991477n; + + const rootFilter = { + [field]: { + _eq: bigintId.toString(), + }, + }; + + const { query } = applyFilter(db, BIGINT_FAKE_SCHEMA, queryBuilder, rootFilter, collection, {}); + + const tracker = createTracker(db); + tracker.on.select('*').response([]); + + await query; + + const resultingSelectQuery = tracker.history.select[0]; + const expectedSql = `select * where "${collection}"."${field}" = ?`; + + expect(resultingSelectQuery?.sql).toEqual(expectedSql); + expect(resultingSelectQuery?.bindings[0]).toEqual(bigintId); + }); }); diff --git a/api/src/utils/apply-query.ts b/api/src/utils/apply-query.ts index 4562418024..ca41af845b 100644 --- a/api/src/utils/apply-query.ts +++ b/api/src/utils/apply-query.ts @@ -644,8 +644,10 @@ export function applyFilter( const functionName = column!.split('(')[0] as FieldFunction; const type = getOutputTypeForFunction(functionName); - if (['bigInteger', 'integer', 'float', 'decimal'].includes(type)) { + if (['integer', 'float', 'decimal'].includes(type)) { compareValue = Number(compareValue); + } else if (type === 'bigInteger') { + compareValue = BigInt(compareValue); } } @@ -664,13 +666,21 @@ export function applyFilter( } } - if (['bigInteger', 'integer', 'float', 'decimal'].includes(type)) { + if (['integer', 'float', 'decimal'].includes(type)) { if (Array.isArray(compareValue)) { compareValue = compareValue.map((val) => Number(val)); } else { compareValue = Number(compareValue); } } + + if (type === 'bigInteger') { + if (Array.isArray(compareValue)) { + compareValue = compareValue.map((val) => BigInt(val)); + } else { + compareValue = BigInt(compareValue); + } + } } if (operator === '_eq') {