From cdf2eead7ebd9f14e0c20e7e23fa605ad2b8d181 Mon Sep 17 00:00:00 2001 From: EmaToplek Date: Fri, 21 Aug 2026 08:32:50 +0200 Subject: [PATCH] test: add coverage for lower-sql-plan.ts literal-unwrap and bind-site guard paths Signed-off-by: EmaToplek --- .../5-runtime/test/lower-sql-plan.test.ts | 73 +++++++++++++++++++ packages/2-sql/5-runtime/vitest.config.ts | 1 - 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 packages/2-sql/5-runtime/test/lower-sql-plan.test.ts diff --git a/packages/2-sql/5-runtime/test/lower-sql-plan.test.ts b/packages/2-sql/5-runtime/test/lower-sql-plan.test.ts new file mode 100644 index 000000000000..a0d2401e132e --- /dev/null +++ b/packages/2-sql/5-runtime/test/lower-sql-plan.test.ts @@ -0,0 +1,73 @@ +import { + BinaryExpr, + ColumnRef, + ParamRef, + PreparedParamRef, + ProjectionItem, + SelectAst, + TableSource, +} from '@internal/sql-relational-core/ast'; +import type { SqlQueryPlan } from '@internal/sql-relational-core/plan'; +import { describe, expect, it } from 'vitest'; +import { lowerSqlPlan } from '../src/lower-sql-plan'; +import { createStubAdapter, createTestContract } from './utils'; + +const testContract = createTestContract({ targetFamily: 'sql', target: 'postgres' }); + +const meta = { + target: testContract.target, + storageHash: testContract.storage.storageHash, + lane: 'dsl' as const, +}; + +function buildLiteralPlan(): SqlQueryPlan<{ id: number }> { + const users = TableSource.named('users'); + const ast = SelectAst.from(users) + .withProjection([ + ProjectionItem.of('id', ColumnRef.of('id', 'users'), { codecId: 'pg/int4@1' }), + ]) + .withWhere( + BinaryExpr.eq( + ColumnRef.of('id', 'users'), + ParamRef.of(42, { codec: { codecId: 'pg/int4@1' } }), + ), + ); + return Object.freeze({ ast, params: [42], meta }); +} + +function buildBindSitePlan(): SqlQueryPlan<{ id: number }> { + const users = TableSource.named('users'); + const ast = SelectAst.from(users) + .withProjection([ + ProjectionItem.of('id', ColumnRef.of('id', 'users'), { codecId: 'pg/int4@1' }), + ]) + .withWhere( + BinaryExpr.eq( + ColumnRef.of('id', 'users'), + PreparedParamRef.of('userId', { codecId: 'pg/int4@1' }), + ), + ); + return Object.freeze({ ast, params: [undefined], meta }); +} + +describe('lowerSqlPlan', () => { + it('unwraps literal slots into a bare-value params array and freezes the result', () => { + const adapter = createStubAdapter(); + const plan = lowerSqlPlan(adapter, testContract, buildLiteralPlan()); + + expect(plan.params).toEqual([42]); + expect(plan.ast).toBeDefined(); + expect(plan.meta).toEqual(meta); + expect(Object.isFrozen(plan)).toBe(true); + }); + + it('throws RUNTIME.PREPARE_BIND_ON_ADHOC when a bind-site slot reaches the ad-hoc path', () => { + const adapter = createStubAdapter(); + expect(() => lowerSqlPlan(adapter, testContract, buildBindSitePlan())).toThrowError( + expect.objectContaining({ + code: 'RUNTIME.PREPARE_BIND_ON_ADHOC', + details: expect.objectContaining({ name: 'userId' }), + }), + ); + }); +}); diff --git a/packages/2-sql/5-runtime/vitest.config.ts b/packages/2-sql/5-runtime/vitest.config.ts index de0b9e499b71..64e635b6831c 100644 --- a/packages/2-sql/5-runtime/vitest.config.ts +++ b/packages/2-sql/5-runtime/vitest.config.ts @@ -18,7 +18,6 @@ export default defineConfig({ '**/*.test-d.ts', '**/*.config.ts', '**/exports/**', - 'src/lower-sql-plan.ts', // TODO(TML-1786): Add tests - currently 0% coverage 'src/codecs/encoding.ts', // TODO(TML-1786): Add tests - currently 6% coverage 'src/codecs/decoding.ts', // TODO(TML-1786): Add tests - currently 33% coverage 'src/codecs/validation.ts', // TODO(TML-1786): Add tests - currently 50% coverage