From 421ae90c1b7b16bae060e1284da9780119ca405b Mon Sep 17 00:00:00 2001 From: sravan27 Date: Thu, 21 May 2026 10:57:00 +0530 Subject: [PATCH] Fix Sync Streams division by zero semantics --- .changeset/quiet-lemons-divide.md | 5 +++++ packages/sync-rules/src/sql_functions.ts | 4 ++++ packages/sync-rules/test/src/sql_operators.test.ts | 8 ++++++++ 3 files changed, 17 insertions(+) create mode 100644 .changeset/quiet-lemons-divide.md diff --git a/.changeset/quiet-lemons-divide.md b/.changeset/quiet-lemons-divide.md new file mode 100644 index 000000000..59f319857 --- /dev/null +++ b/.changeset/quiet-lemons-divide.md @@ -0,0 +1,5 @@ +--- +"@powersync/service-sync-rules": patch +--- + +Fix Sync Streams division by zero semantics diff --git a/packages/sync-rules/src/sql_functions.ts b/packages/sync-rules/src/sql_functions.ts index a7fb98303..26382feb3 100644 --- a/packages/sync-rules/src/sql_functions.ts +++ b/packages/sync-rules/src/sql_functions.ts @@ -744,6 +744,10 @@ function doMath(op: string, a: SqliteValue, b: SqliteValue) { let na = cast(a, 'numeric') as number | bigint; let nb = cast(b, 'numeric') as number | bigint; + if (op == '/' && nb == 0) { + return null; + } + if (typeof na == 'bigint' && typeof nb != 'bigint') { // bigint, real na = Number(na); diff --git a/packages/sync-rules/test/src/sql_operators.test.ts b/packages/sync-rules/test/src/sql_operators.test.ts index 6dfa95dee..357e80188 100644 --- a/packages/sync-rules/test/src/sql_operators.test.ts +++ b/packages/sync-rules/test/src/sql_operators.test.ts @@ -110,6 +110,14 @@ describe('SQL operators', () => { expect(evaluateOperator('/', 5n, '2.0')).toStrictEqual(2.5); }); + test('division by zero follows SQLite null semantics', () => { + expect(evaluateOperator('/', 5n, 0n)).toStrictEqual(null); + expect(evaluateOperator('/', 5n, 0)).toStrictEqual(null); + expect(evaluateOperator('/', 5, 0)).toStrictEqual(null); + expect(evaluateOperator('/', -5n, '0')).toStrictEqual(null); + expect(evaluateOperator('/', 0n, 0n)).toStrictEqual(null); + }); + test('*', () => { expect(evaluateOperator('*', 3n, null)).toStrictEqual(null); expect(evaluateOperator('*', 3n, 2)).toStrictEqual(6);