@prisma-next/sql-runtime 0.3.0-dev.3 → 0.3.0-dev.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +1 -2
  2. package/dist/{accelerate-EEKAFGN3-SHR4XFVV.js → accelerate-EEKAFGN3-P6A6XJWJ.js} +28 -28
  3. package/dist/{accelerate-EEKAFGN3-SHR4XFVV.js.map → accelerate-EEKAFGN3-P6A6XJWJ.js.map} +1 -1
  4. package/dist/{chunk-C6I3V3DM.js → chunk-APA6GHYY.js} +84 -2
  5. package/dist/chunk-APA6GHYY.js.map +1 -0
  6. package/dist/{dist-LCVVJCGI.js → dist-AQ3LWXOX.js} +13 -13
  7. package/dist/{dist-LCVVJCGI.js.map → dist-AQ3LWXOX.js.map} +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/src/codecs/decoding.d.ts +4 -0
  10. package/dist/src/codecs/decoding.d.ts.map +1 -0
  11. package/dist/src/codecs/encoding.d.ts +5 -0
  12. package/dist/src/codecs/encoding.d.ts.map +1 -0
  13. package/dist/src/codecs/validation.d.ts +6 -0
  14. package/dist/src/codecs/validation.d.ts.map +1 -0
  15. package/dist/src/exports/index.d.ts +11 -0
  16. package/dist/src/exports/index.d.ts.map +1 -0
  17. package/dist/src/index.d.ts +2 -0
  18. package/dist/src/index.d.ts.map +1 -0
  19. package/dist/src/lower-sql-plan.d.ts +15 -0
  20. package/dist/src/lower-sql-plan.d.ts.map +1 -0
  21. package/dist/src/sql-context.d.ts +130 -0
  22. package/dist/src/sql-context.d.ts.map +1 -0
  23. package/dist/src/sql-family-adapter.d.ts +10 -0
  24. package/dist/src/sql-family-adapter.d.ts.map +1 -0
  25. package/dist/src/sql-marker.d.ts +22 -0
  26. package/dist/src/sql-marker.d.ts.map +1 -0
  27. package/dist/src/sql-runtime.d.ts +25 -0
  28. package/dist/src/sql-runtime.d.ts.map +1 -0
  29. package/dist/test/utils.d.ts +20 -24
  30. package/dist/test/utils.d.ts.map +1 -0
  31. package/dist/test/utils.js +26 -26
  32. package/dist/test/utils.js.map +1 -1
  33. package/package.json +25 -22
  34. package/src/codecs/decoding.ts +140 -0
  35. package/src/codecs/encoding.ts +76 -0
  36. package/src/codecs/validation.ts +67 -0
  37. package/src/exports/index.ts +40 -0
  38. package/src/index.ts +1 -0
  39. package/src/lower-sql-plan.ts +32 -0
  40. package/src/sql-context.ts +402 -0
  41. package/src/sql-family-adapter.ts +43 -0
  42. package/src/sql-marker.ts +105 -0
  43. package/src/sql-runtime.ts +166 -0
  44. package/test/async-iterable-result.test.ts +136 -0
  45. package/test/context.types.test-d.ts +70 -0
  46. package/test/parameterized-types.test.ts +553 -0
  47. package/test/sql-context.test.ts +217 -0
  48. package/test/sql-family-adapter.test.ts +86 -0
  49. package/test/sql-runtime.test.ts +155 -0
  50. package/test/utils.ts +266 -0
  51. package/dist/chunk-C6I3V3DM.js.map +0 -1
  52. package/dist/index.d.ts +0 -29
  53. package/dist/sql-runtime-DgEbg2OP.d.ts +0 -109
@@ -0,0 +1,166 @@
1
+ import type { ExecutionPlan } from '@prisma-next/contract/types';
2
+ import type { OperationRegistry } from '@prisma-next/operations';
3
+ import type {
4
+ Log,
5
+ Plugin,
6
+ RuntimeCore,
7
+ RuntimeCoreOptions,
8
+ RuntimeTelemetryEvent,
9
+ RuntimeVerifyOptions,
10
+ TelemetryOutcome,
11
+ } from '@prisma-next/runtime-executor';
12
+ import { AsyncIterableResult, createRuntimeCore } from '@prisma-next/runtime-executor';
13
+ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
14
+ import type {
15
+ Adapter,
16
+ CodecRegistry,
17
+ LoweredStatement,
18
+ SelectAst,
19
+ SqlDriver,
20
+ } from '@prisma-next/sql-relational-core/ast';
21
+ import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
22
+ import { decodeRow } from './codecs/decoding';
23
+ import { encodeParams } from './codecs/encoding';
24
+ import { validateCodecRegistryCompleteness } from './codecs/validation';
25
+ import { lowerSqlPlan } from './lower-sql-plan';
26
+ import type { RuntimeContext } from './sql-context';
27
+ import { SqlFamilyAdapter } from './sql-family-adapter';
28
+
29
+ export interface RuntimeOptions<
30
+ TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>,
31
+ > {
32
+ readonly driver: SqlDriver;
33
+ readonly verify: RuntimeVerifyOptions;
34
+ readonly context: RuntimeContext<TContract>;
35
+ readonly plugins?: readonly Plugin<
36
+ TContract,
37
+ Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
38
+ SqlDriver
39
+ >[];
40
+ readonly mode?: 'strict' | 'permissive';
41
+ readonly log?: Log;
42
+ }
43
+
44
+ export interface Runtime {
45
+ execute<Row = Record<string, unknown>>(
46
+ plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
47
+ ): AsyncIterableResult<Row>;
48
+ telemetry(): RuntimeTelemetryEvent | null;
49
+ close(): Promise<void>;
50
+ operations(): OperationRegistry;
51
+ }
52
+
53
+ export type { RuntimeTelemetryEvent, RuntimeVerifyOptions, TelemetryOutcome };
54
+
55
+ class SqlRuntimeImpl<TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>>
56
+ implements Runtime
57
+ {
58
+ private readonly core: RuntimeCore<
59
+ TContract,
60
+ Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
61
+ SqlDriver
62
+ >;
63
+ private readonly contract: TContract;
64
+ private readonly context: RuntimeContext<TContract>;
65
+ private readonly codecRegistry: CodecRegistry;
66
+ private codecRegistryValidated: boolean;
67
+
68
+ constructor(options: RuntimeOptions<TContract>) {
69
+ const { context, driver, verify, plugins, mode, log } = options;
70
+ this.contract = context.contract;
71
+ this.context = context;
72
+ this.codecRegistry = context.codecs;
73
+ this.codecRegistryValidated = false;
74
+
75
+ const familyAdapter = new SqlFamilyAdapter(context.contract);
76
+
77
+ const coreOptions: RuntimeCoreOptions<
78
+ TContract,
79
+ Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
80
+ SqlDriver
81
+ > = {
82
+ familyAdapter,
83
+ driver,
84
+ verify,
85
+ plugins: plugins as readonly Plugin<
86
+ TContract,
87
+ Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
88
+ SqlDriver
89
+ >[],
90
+ ...(mode !== undefined ? { mode } : {}),
91
+ ...(log !== undefined ? { log } : {}),
92
+ operationRegistry: context.operations,
93
+ };
94
+
95
+ this.core = createRuntimeCore(coreOptions);
96
+
97
+ if (verify.mode === 'startup') {
98
+ validateCodecRegistryCompleteness(this.codecRegistry, context.contract);
99
+ this.codecRegistryValidated = true;
100
+ }
101
+ }
102
+
103
+ private ensureCodecRegistryValidated(contract: SqlContract<SqlStorage>): void {
104
+ if (!this.codecRegistryValidated) {
105
+ validateCodecRegistryCompleteness(this.codecRegistry, contract);
106
+ this.codecRegistryValidated = true;
107
+ }
108
+ }
109
+
110
+ execute<Row = Record<string, unknown>>(
111
+ plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
112
+ ): AsyncIterableResult<Row> {
113
+ this.ensureCodecRegistryValidated(this.contract);
114
+
115
+ // Check if plan is SqlQueryPlan (has ast but no sql)
116
+ const isSqlQueryPlan = (p: ExecutionPlan<Row> | SqlQueryPlan<Row>): p is SqlQueryPlan<Row> => {
117
+ return 'ast' in p && !('sql' in p);
118
+ };
119
+
120
+ // Lower SqlQueryPlan to Plan if needed
121
+ const executablePlan: ExecutionPlan<Row> = isSqlQueryPlan(plan)
122
+ ? lowerSqlPlan(this.context, plan)
123
+ : plan;
124
+
125
+ const iterator = async function* (
126
+ self: SqlRuntimeImpl<TContract>,
127
+ ): AsyncGenerator<Row, void, unknown> {
128
+ const encodedParams = encodeParams(executablePlan, self.codecRegistry);
129
+ const planWithEncodedParams: ExecutionPlan<Row> = {
130
+ ...executablePlan,
131
+ params: encodedParams,
132
+ };
133
+
134
+ const coreIterator = self.core.execute(planWithEncodedParams);
135
+
136
+ for await (const rawRow of coreIterator) {
137
+ const decodedRow = decodeRow(
138
+ rawRow as Record<string, unknown>,
139
+ executablePlan,
140
+ self.codecRegistry,
141
+ );
142
+ yield decodedRow as Row;
143
+ }
144
+ };
145
+
146
+ return new AsyncIterableResult(iterator(this));
147
+ }
148
+
149
+ telemetry(): RuntimeTelemetryEvent | null {
150
+ return this.core.telemetry();
151
+ }
152
+
153
+ operations(): OperationRegistry {
154
+ return this.core.operations();
155
+ }
156
+
157
+ close(): Promise<void> {
158
+ return this.core.close();
159
+ }
160
+ }
161
+
162
+ export function createRuntime<TContract extends SqlContract<SqlStorage>>(
163
+ options: RuntimeOptions<TContract>,
164
+ ): Runtime {
165
+ return new SqlRuntimeImpl(options);
166
+ }
@@ -0,0 +1,136 @@
1
+ import type { ExecutionPlan } from '@prisma-next/contract/types';
2
+ import type { AsyncIterableResult } from '@prisma-next/runtime-executor';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { createRuntime } from '../src/exports';
5
+ import { createStubAdapter, createTestContext, createTestContract } from './utils';
6
+
7
+ // Mock driver that implements SqlDriver interface
8
+ class MockDriver {
9
+ private rows: ReadonlyArray<Record<string, unknown>> = [];
10
+
11
+ setRows(rows: ReadonlyArray<Record<string, unknown>>): void {
12
+ this.rows = rows;
13
+ }
14
+
15
+ async query(
16
+ _sql: string,
17
+ _params: readonly unknown[],
18
+ ): Promise<{ rows: ReadonlyArray<unknown> }> {
19
+ // Return empty marker result for contract verification
20
+ return { rows: [] };
21
+ }
22
+
23
+ async *execute<Row = Record<string, unknown>>(_options: {
24
+ sql: string;
25
+ params: readonly unknown[];
26
+ }): AsyncIterable<Row> {
27
+ for (const row of this.rows) {
28
+ yield row as Row;
29
+ }
30
+ }
31
+
32
+ async connect(): Promise<void> {
33
+ // No-op
34
+ }
35
+
36
+ async close(): Promise<void> {
37
+ // No-op
38
+ }
39
+ }
40
+
41
+ const fixtureContract = createTestContract({
42
+ schemaVersion: '1',
43
+ targetFamily: 'sql',
44
+ target: 'postgres',
45
+ coreHash: 'test-hash',
46
+ profileHash: 'test-profile-hash',
47
+ storage: {
48
+ tables: {
49
+ user: {
50
+ columns: {
51
+ id: { nativeType: 'int4', codecId: 'pg/int4@1', nullable: false },
52
+ email: { nativeType: 'text', codecId: 'pg/text@1', nullable: false },
53
+ },
54
+ uniques: [],
55
+ indexes: [],
56
+ foreignKeys: [],
57
+ },
58
+ },
59
+ },
60
+ models: {},
61
+ relations: {},
62
+ mappings: { codecTypes: {}, operationTypes: {} },
63
+ });
64
+
65
+ describe('SqlRuntime AsyncIterableResult integration', () => {
66
+ it('returns AsyncIterableResult from execute', async () => {
67
+ const adapter = createStubAdapter();
68
+ const driver = new MockDriver();
69
+ driver.setRows([
70
+ { id: 1, email: 'test1@example.com' },
71
+ { id: 2, email: 'test2@example.com' },
72
+ ]);
73
+ const context = createTestContext(fixtureContract, adapter);
74
+ const runtime = createRuntime({
75
+ driver: driver as unknown as Parameters<typeof createRuntime>[0]['driver'],
76
+ context,
77
+ verify: { mode: 'onFirstUse', requireMarker: false },
78
+ });
79
+
80
+ const plan: ExecutionPlan<{ id: number; email: string }> = {
81
+ sql: 'SELECT id, email FROM "user" ORDER BY id',
82
+ params: [],
83
+ meta: {
84
+ target: 'postgres',
85
+ targetFamily: 'sql',
86
+ coreHash: 'test-hash',
87
+ lane: 'sql',
88
+ paramDescriptors: [],
89
+ },
90
+ };
91
+
92
+ const result = runtime.execute(plan);
93
+
94
+ // Verify it's an AsyncIterableResult
95
+ expect(result).toBeInstanceOf(Object);
96
+ expect(typeof result.toArray).toBe('function');
97
+ expect(typeof result[Symbol.asyncIterator]).toBe('function');
98
+
99
+ await runtime.close();
100
+ });
101
+
102
+ it('preserves type information', async () => {
103
+ const adapter = createStubAdapter();
104
+ const driver = new MockDriver();
105
+ driver.setRows([{ id: 1, email: 'test@example.com' }]);
106
+ const context = createTestContext(fixtureContract, adapter);
107
+ const runtime = createRuntime({
108
+ driver: driver as unknown as Parameters<typeof createRuntime>[0]['driver'],
109
+ context,
110
+ verify: { mode: 'onFirstUse', requireMarker: false },
111
+ });
112
+
113
+ const plan: ExecutionPlan<{ id: number; email: string }> = {
114
+ sql: 'SELECT id, email FROM "user" LIMIT 1',
115
+ params: [],
116
+ meta: {
117
+ target: 'postgres',
118
+ targetFamily: 'sql',
119
+ coreHash: 'test-hash',
120
+ lane: 'sql',
121
+ paramDescriptors: [],
122
+ },
123
+ };
124
+
125
+ const result: AsyncIterableResult<{ id: number; email: string }> = runtime.execute(plan);
126
+ const rows = await result.toArray();
127
+
128
+ expect(rows.length).toBe(1);
129
+ if (rows[0]) {
130
+ expect(typeof rows[0].id).toBe('number');
131
+ expect(typeof rows[0].email).toBe('string');
132
+ }
133
+
134
+ await runtime.close();
135
+ });
136
+ });
@@ -0,0 +1,70 @@
1
+ import type { SqlContract, SqlMappings, SqlStorage } from '@prisma-next/sql-contract/types';
2
+ import { expectTypeOf, test } from 'vitest';
3
+ import type { RuntimeContext, TypeHelperRegistry } from '../src/sql-context';
4
+
5
+ // Contract type with storage.types using literal types (matching emission output)
6
+ type TestContract = SqlContract<
7
+ {
8
+ readonly tables: {
9
+ readonly document: {
10
+ readonly columns: {
11
+ readonly id: {
12
+ readonly nativeType: 'int4';
13
+ readonly codecId: 'pg/int4@1';
14
+ nullable: false;
15
+ };
16
+ };
17
+ readonly primaryKey: { readonly columns: readonly ['id'] };
18
+ readonly uniques: readonly [];
19
+ readonly indexes: readonly [];
20
+ readonly foreignKeys: readonly [];
21
+ };
22
+ };
23
+ readonly types: {
24
+ readonly Vector1536: {
25
+ readonly codecId: 'pg/vector@1';
26
+ readonly nativeType: 'vector';
27
+ readonly typeParams: { readonly length: 1536 };
28
+ };
29
+ };
30
+ },
31
+ Record<string, never>,
32
+ Record<string, never>,
33
+ SqlMappings
34
+ >;
35
+
36
+ test('RuntimeContext.types is TypeHelperRegistry', () => {
37
+ // RuntimeContext.types is intentionally loose (Record<string, unknown>)
38
+ // The strong typing comes from schema(context).types via ExtractSchemaTypes
39
+ expectTypeOf<RuntimeContext<TestContract>['types']>().toEqualTypeOf<
40
+ TypeHelperRegistry | undefined
41
+ >();
42
+
43
+ // TypeHelperRegistry allows any values - the actual type depends on init hooks
44
+ expectTypeOf<TypeHelperRegistry>().toEqualTypeOf<Record<string, unknown>>();
45
+ });
46
+
47
+ test('RuntimeContext preserves contract type parameter', () => {
48
+ // Verify the contract type is preserved in RuntimeContext
49
+ expectTypeOf<RuntimeContext<TestContract>['contract']>().toEqualTypeOf<TestContract>();
50
+
51
+ // Verify we can access storage.types through the context's contract
52
+ type ContractStorageTypes = RuntimeContext<TestContract>['contract']['storage']['types'];
53
+ expectTypeOf<ContractStorageTypes>().toExtend<
54
+ | {
55
+ readonly Vector1536: {
56
+ readonly codecId: 'pg/vector@1';
57
+ readonly nativeType: 'vector';
58
+ readonly typeParams: { readonly length: 1536 };
59
+ };
60
+ }
61
+ | undefined
62
+ >();
63
+ });
64
+
65
+ test('RuntimeContext accepts generic SqlContract', () => {
66
+ // Verify RuntimeContext defaults work
67
+ type DefaultContext = RuntimeContext;
68
+ expectTypeOf<DefaultContext['contract']>().toExtend<SqlContract<SqlStorage>>();
69
+ expectTypeOf<DefaultContext['types']>().toEqualTypeOf<TypeHelperRegistry | undefined>();
70
+ });