@prisma-next/sql-runtime 0.9.0-dev.1 → 0.9.0-dev.3
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.
- package/dist/{exports-C2zFVOFS.mjs → exports-DHQOSWty.mjs} +231 -64
- package/dist/exports-DHQOSWty.mjs.map +1 -0
- package/dist/{index-BhG8bX80.d.mts → index-B2sP_QGE.d.mts} +101 -52
- package/dist/index-B2sP_QGE.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/test/utils.d.mts +4 -3
- package/dist/test/utils.d.mts.map +1 -1
- package/dist/test/utils.mjs +15 -4
- package/dist/test/utils.mjs.map +1 -1
- package/package.json +12 -12
- package/src/codecs/decoding.ts +6 -25
- package/src/codecs/encoding.ts +29 -20
- package/src/exports/index.ts +10 -0
- package/src/lower-sql-plan.ts +16 -5
- package/src/middleware/budgets.ts +4 -1
- package/src/prepared/bind-site-params.ts +41 -0
- package/src/prepared/encode-prepared.ts +41 -0
- package/src/prepared/prepared-statement.ts +50 -0
- package/src/prepared/types.ts +65 -0
- package/src/sql-runtime.ts +289 -55
- package/dist/exports-C2zFVOFS.mjs.map +0 -1
- package/dist/index-BhG8bX80.d.mts.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { APP_SPACE_ID, AfterExecuteResult, BudgetsOptions, CreateRuntimeOptions, ExecutionContext, GeneratorStability, LintsOptions, Log, MarkerReadResult, MarkerReader, MarkerStatement, Runtime, RuntimeConnection, RuntimeFamilyAdapter, RuntimeMutationDefaultGenerator, RuntimeParameterizedCodecDescriptor, RuntimeQueryable, RuntimeTelemetryEvent, RuntimeTransaction, RuntimeVerifyOptions, SqlExecutionStack, SqlExecutionStackWithDriver, SqlMiddleware, SqlMiddlewareContext, SqlRuntimeAdapterDescriptor, SqlRuntimeAdapterInstance, SqlRuntimeDriverInstance, SqlRuntimeExtensionDescriptor, SqlRuntimeExtensionInstance, SqlRuntimeTargetDescriptor, SqlStatement, SqlStaticContributions, TelemetryOutcome, TransactionContext, TypeHelperRegistry, budgets, createExecutionContext, createRuntime, createSqlExecutionStack, ensureSchemaStatement, ensureTableStatement, extractCodecIds, lints, lowerSqlPlan, parseContractMarkerRow, readContractMarker, validateCodecRegistryCompleteness, validateContractCodecMappings, withTransaction, writeContractMarker };
|
|
1
|
+
import { $ as SqlMiddlewareContext, A as RuntimeParameterizedCodecDescriptor, B as TypeHelperRegistry, C as RuntimeTransaction, D as ExecutionContext, E as withTransaction, F as SqlRuntimeDriverInstance, G as RuntimeTelemetryEvent, H as createSqlExecutionStack, I as SqlRuntimeExtensionDescriptor, J as LintsOptions, K as RuntimeVerifyOptions, L as SqlRuntimeExtensionInstance, M as SqlExecutionStackWithDriver, N as SqlRuntimeAdapterDescriptor, O as GeneratorStability, P as SqlRuntimeAdapterInstance, Q as SqlMiddleware, R as SqlRuntimeTargetDescriptor, S as RuntimeQueryable, T as createRuntime, U as MarkerReader, V as createExecutionContext, W as RuntimeFamilyAdapter, X as BudgetsOptions, Y as lints, Z as budgets, _ as PrepareCallback, a as APP_SPACE_ID, b as Runtime, c as ensureTableStatement, d as BindSiteParams, et as parseContractMarkerRow, f as Declaration, g as ParamsFromDeclaration, h as ParamSpec, i as MarkerStatement, it as validateContractCodecMappings, j as SqlExecutionStack, k as RuntimeMutationDefaultGenerator, l as readContractMarker, m as DeclaredNullable, n as Log, nt as extractCodecIds, o as SqlStatement, p as DeclaredCodecId, q as TelemetryOutcome, r as MarkerReadResult, rt as validateCodecRegistryCompleteness, s as ensureSchemaStatement, t as AfterExecuteResult, tt as lowerSqlPlan, u as writeContractMarker, v as PreparedStatement, w as TransactionContext, x as RuntimeConnection, y as CreateRuntimeOptions, z as SqlStaticContributions } from "./index-B2sP_QGE.mjs";
|
|
2
|
+
export { APP_SPACE_ID, AfterExecuteResult, BindSiteParams, BudgetsOptions, CreateRuntimeOptions, Declaration, DeclaredCodecId, DeclaredNullable, ExecutionContext, GeneratorStability, LintsOptions, Log, MarkerReadResult, MarkerReader, MarkerStatement, ParamSpec, ParamsFromDeclaration, PrepareCallback, PreparedStatement, Runtime, RuntimeConnection, RuntimeFamilyAdapter, RuntimeMutationDefaultGenerator, RuntimeParameterizedCodecDescriptor, RuntimeQueryable, RuntimeTelemetryEvent, RuntimeTransaction, RuntimeVerifyOptions, SqlExecutionStack, SqlExecutionStackWithDriver, SqlMiddleware, SqlMiddlewareContext, SqlRuntimeAdapterDescriptor, SqlRuntimeAdapterInstance, SqlRuntimeDriverInstance, SqlRuntimeExtensionDescriptor, SqlRuntimeExtensionInstance, SqlRuntimeTargetDescriptor, SqlStatement, SqlStaticContributions, TelemetryOutcome, TransactionContext, TypeHelperRegistry, budgets, createExecutionContext, createRuntime, createSqlExecutionStack, ensureSchemaStatement, ensureTableStatement, extractCodecIds, lints, lowerSqlPlan, parseContractMarkerRow, readContractMarker, validateCodecRegistryCompleteness, validateContractCodecMappings, withTransaction, writeContractMarker };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ensureTableStatement, c as createExecutionContext, d as budgets, f as parseContractMarkerRow, g as validateContractCodecMappings, h as validateCodecRegistryCompleteness, i as ensureSchemaStatement, l as createSqlExecutionStack, m as extractCodecIds, n as withTransaction, o as readContractMarker, p as lowerSqlPlan, r as APP_SPACE_ID, s as writeContractMarker, t as createRuntime, u as lints } from "./exports-
|
|
1
|
+
import { a as ensureTableStatement, c as createExecutionContext, d as budgets, f as parseContractMarkerRow, g as validateContractCodecMappings, h as validateCodecRegistryCompleteness, i as ensureSchemaStatement, l as createSqlExecutionStack, m as extractCodecIds, n as withTransaction, o as readContractMarker, p as lowerSqlPlan, r as APP_SPACE_ID, s as writeContractMarker, t as createRuntime, u as lints } from "./exports-DHQOSWty.mjs";
|
|
2
2
|
export { APP_SPACE_ID, budgets, createExecutionContext, createRuntime, createSqlExecutionStack, ensureSchemaStatement, ensureTableStatement, extractCodecIds, lints, lowerSqlPlan, parseContractMarkerRow, readContractMarker, validateCodecRegistryCompleteness, validateContractCodecMappings, withTransaction, writeContractMarker };
|
package/dist/test/utils.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as ExecutionContext, F as SqlRuntimeDriverInstance, I as SqlRuntimeExtensionDescriptor, L as SqlRuntimeExtensionInstance, N as SqlRuntimeAdapterDescriptor, P as SqlRuntimeAdapterInstance, R as SqlRuntimeTargetDescriptor, T as createRuntime, o as SqlStatement } from "../index-B2sP_QGE.mjs";
|
|
2
2
|
import { ResultType } from "@prisma-next/framework-components/runtime";
|
|
3
|
-
import { Adapter, Codec, ContractCodecRegistry, LoweredStatement, SelectAst } from "@prisma-next/sql-relational-core/ast";
|
|
3
|
+
import { Adapter, AnyQueryAst, Codec, ContractCodecRegistry, LoweredStatement, SelectAst } from "@prisma-next/sql-relational-core/ast";
|
|
4
4
|
import * as _$_prisma_next_framework_components_execution0 from "@prisma-next/framework-components/execution";
|
|
5
5
|
import { RuntimeDriverDescriptor } from "@prisma-next/framework-components/execution";
|
|
6
6
|
import { SqlStorage, SqlStorageInput } from "@prisma-next/sql-contract/types";
|
|
@@ -77,6 +77,7 @@ declare function createTestContract(contract: Partial<Omit<Contract<SqlStorage>,
|
|
|
77
77
|
profileHash?: string;
|
|
78
78
|
storage?: Omit<SqlStorageInput, 'storageHash'>;
|
|
79
79
|
}): Contract<SqlStorage>;
|
|
80
|
+
declare function stubAst(): AnyQueryAst;
|
|
80
81
|
//#endregion
|
|
81
|
-
export { type DevDatabase, StubAdapter, buildTestContractCodecs, collectAsync, createDevDatabase, createStubAdapter, createTestAdapterDescriptor, createTestContext, createTestContract, createTestStackInstance, createTestTargetDescriptor, descriptorsFromCodecs, drainPlanExecution, executePlanAndCollect, executeStatement, setupTestDatabase, teardownTestDatabase, withClient, writeTestContractMarker };
|
|
82
|
+
export { type DevDatabase, StubAdapter, buildTestContractCodecs, collectAsync, createDevDatabase, createStubAdapter, createTestAdapterDescriptor, createTestContext, createTestContract, createTestStackInstance, createTestTargetDescriptor, descriptorsFromCodecs, drainPlanExecution, executePlanAndCollect, executeStatement, setupTestDatabase, stubAst, teardownTestDatabase, withClient, writeTestContractMarker };
|
|
82
83
|
//# sourceMappingURL=utils.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.mts","names":[],"sources":["../../test/utils.ts"],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"utils.d.mts","names":[],"sources":["../../test/utils.ts"],"mappings":";;;;;;;;;;;;;;;AA4DA;iBAAsB,qBAAA,WACV,gBAAA,CAAiB,UAAA,CAAW,CAAA,KAAM,YAAA,CAAa,UAAA,CAAW,CAAA,GAAA,CACpE,OAAA,EAAS,UAAA,QAAkB,aAAA,GAAgB,IAAA,EAAM,CAAA,GAAI,OAAA,CAAQ,UAAA,CAAW,CAAA;;;;iBAQpD,kBAAA,CACpB,OAAA,EAAS,UAAA,QAAkB,aAAA,GAC3B,IAAA,EAAM,gBAAA,GAAmB,YAAA,YACxB,OAAA;;;;iBAOmB,gBAAA,CAAiB,MAAA,EAAQ,MAAA,EAAQ,SAAA,EAAW,YAAA,GAAe,OAAA;;;;iBAY3D,iBAAA,CACpB,MAAA,EAAQ,MAAA,EACR,QAAA,EAAU,QAAA,CAAS,UAAA,GACnB,OAAA,GAAU,MAAA,EAAQ,MAAA,KAAW,OAAA,SAC5B,OAAA;;;;iBAqBmB,uBAAA,CACpB,MAAA,EAAQ,MAAA,EACR,QAAA,EAAU,QAAA,CAAS,UAAA,IAClB,OAAA;;;;;;;iBAiBa,uBAAA,CACd,MAAA,EAAQ,aAAA,CAAc,KAAA,YACrB,qBAAA;;;;;iBAqCa,qBAAA,CACd,MAAA,EAAQ,aAAA,CAAc,KAAA,YACrB,aAAA,CAAc,eAAA;AAAA,iBAuCD,2BAAA,CACd,OAAA,EAAS,WAAA,GACR,2BAAA;;;;iBAmBa,0BAAA,CAAA,GAA8B,0BAAA;;;;;;iBAmB9B,iBAAA,mBAAoC,QAAA,CAAS,UAAA,EAAA,CAC3D,QAAA,EAAU,SAAA,EACV,OAAA,EAAS,WAAA,EACT,OAAA;EACE,cAAA,GAAiB,aAAA,CAAc,6BAAA;AAAA,IAEhC,gBAAA,CAAiB,SAAA;AAAA,iBAWJ,uBAAA,CAAwB,OAAA;EACtC,cAAA,GAAiB,aAAA,CAAc,6BAAA;EAC/B,MAAA,GAAS,uBAAA,6BAIP,wBAAA;AAAA,IAEH,8CAAA,CAAA,sBAAA,oBAAA,yBAAA,cAAA,wBAAA,cAAA,2BAAA;;;;KAcW,WAAA,GAAc,OAAA,CAAQ,SAAA,EAAW,QAAA,CAAS,UAAA,GAAa,gBAAA;EAAA,SACxD,QAAA,EAAU,aAAA,CAAc,KAAA;AAAA;AAzNnC;;;;;AAAA,iBAiOgB,iBAAA,CAAA,GAAqB,WAAA;AAAA,iBA0FrB,kBAAA,CACd,QAAA,EAAU,OAAA,CAAQ,IAAA,CAAK,QAAA,CAAS,UAAA;EAC9B,WAAA;EACA,WAAA;EACA,OAAA,GAAU,IAAA,CAAK,eAAA;AAAA,IAEhB,QAAA,CAAS,UAAA;AAAA,iBAoBI,OAAA,CAAA,GAAW,WAAA"}
|
package/dist/test/utils.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { a as ensureTableStatement, c as createExecutionContext, i as ensureSchemaStatement, l as createSqlExecutionStack, r as APP_SPACE_ID, s as writeContractMarker } from "../exports-
|
|
1
|
+
import { a as ensureTableStatement, c as createExecutionContext, i as ensureSchemaStatement, l as createSqlExecutionStack, r as APP_SPACE_ID, s as writeContractMarker } from "../exports-DHQOSWty.mjs";
|
|
2
2
|
import { runtimeError } from "@prisma-next/framework-components/runtime";
|
|
3
|
+
import { SelectAst, TableSource } from "@prisma-next/sql-relational-core/ast";
|
|
3
4
|
import { instantiateExecutionStack } from "@prisma-next/framework-components/execution";
|
|
4
5
|
import { canonicalizeJson } from "@prisma-next/framework-components/utils";
|
|
5
6
|
import { SqlStorage } from "@prisma-next/sql-contract/types";
|
|
@@ -282,11 +283,18 @@ function createStubAdapter() {
|
|
|
282
283
|
capabilities: {},
|
|
283
284
|
readMarker: async () => ({ kind: "absent" })
|
|
284
285
|
},
|
|
285
|
-
lower(ast,
|
|
286
|
+
lower(ast, _ctx) {
|
|
286
287
|
const sqlText = JSON.stringify(ast);
|
|
288
|
+
const params = ast.collectParamRefs().map((ref) => ref.kind === "prepared-param-ref" ? {
|
|
289
|
+
kind: "bind",
|
|
290
|
+
name: ref.name
|
|
291
|
+
} : {
|
|
292
|
+
kind: "literal",
|
|
293
|
+
value: ref.value
|
|
294
|
+
});
|
|
287
295
|
return Object.freeze({
|
|
288
296
|
sql: sqlText,
|
|
289
|
-
params
|
|
297
|
+
params
|
|
290
298
|
});
|
|
291
299
|
}
|
|
292
300
|
};
|
|
@@ -313,7 +321,10 @@ function createTestContract(contract) {
|
|
|
313
321
|
profileHash: profileHash(rest["profileHash"] ?? "sha256:testprofile")
|
|
314
322
|
};
|
|
315
323
|
}
|
|
324
|
+
function stubAst() {
|
|
325
|
+
return SelectAst.from(TableSource.named("stub"));
|
|
326
|
+
}
|
|
316
327
|
//#endregion
|
|
317
|
-
export { buildTestContractCodecs, collectAsync, createDevDatabase, createStubAdapter, createTestAdapterDescriptor, createTestContext, createTestContract, createTestStackInstance, createTestTargetDescriptor, descriptorsFromCodecs, drainPlanExecution, executePlanAndCollect, executeStatement, setupTestDatabase, teardownTestDatabase, withClient, writeTestContractMarker };
|
|
328
|
+
export { buildTestContractCodecs, collectAsync, createDevDatabase, createStubAdapter, createTestAdapterDescriptor, createTestContext, createTestContract, createTestStackInstance, createTestTargetDescriptor, descriptorsFromCodecs, drainPlanExecution, executePlanAndCollect, executeStatement, setupTestDatabase, stubAst, teardownTestDatabase, withClient, writeTestContractMarker };
|
|
318
329
|
|
|
319
330
|
//# sourceMappingURL=utils.mjs.map
|
package/dist/test/utils.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","names":["collectAsync"],"sources":["../../test/test-codec.ts","../../test/utils.ts"],"sourcesContent":["/**\n * Test-only helper that constructs a SQL-family `Codec` instance from author-side encode/decode functions. Replaces the legacy public `mkCodec()` factory (deleted under TML-2357); tests that need a stub codec for behavioural assertions instantiate one through this helper rather than going through `descriptor.factory(...)`.\n *\n * The body is identical in spirit to the retired `mkCodec`: promise-lift sync author functions onto the framework-required `Promise<…>` boundary, default `encodeJson`/`decodeJson` to identity when `TInput` is JSON-safe, fail loudly otherwise.\n */\nimport type { JsonValue } from '@prisma-next/contract/types';\nimport type { CodecTrait } from '@prisma-next/framework-components/codec';\nimport type { Codec, SqlCodecCallContext } from '@prisma-next/sql-relational-core/ast';\n\ntype JsonRoundTripConfig<TInput> = [TInput] extends [JsonValue]\n ? {\n encodeJson?: (value: TInput) => JsonValue;\n decodeJson?: (json: JsonValue) => TInput;\n }\n : {\n encodeJson: (value: TInput) => JsonValue;\n decodeJson: (json: JsonValue) => TInput;\n };\n\nexport function defineTestCodec<\n Id extends string,\n const TTraits extends readonly CodecTrait[] = readonly [],\n TWire = unknown,\n TInput = unknown,\n>(\n config: {\n typeId: Id;\n targetTypes?: readonly string[];\n encode: (value: TInput, ctx: SqlCodecCallContext) => TWire | Promise<TWire>;\n decode: (wire: TWire, ctx: SqlCodecCallContext) => TInput | Promise<TInput>;\n traits?: TTraits;\n } & JsonRoundTripConfig<TInput>,\n): Codec<Id, TTraits, TWire, TInput> {\n const identity = (v: unknown) => v;\n const userEncode = config.encode;\n const userDecode = config.decode;\n const widenedConfig = config as {\n encodeJson?: (value: TInput) => JsonValue;\n decodeJson?: (json: JsonValue) => TInput;\n };\n return {\n id: config.typeId,\n encode: (value, ctx) => {\n try {\n return Promise.resolve(userEncode(value, ctx));\n } catch (error) {\n return Promise.reject(error);\n }\n },\n decode: (wire, ctx) => {\n try {\n return Promise.resolve(userDecode(wire, ctx));\n } catch (error) {\n return Promise.reject(error);\n }\n },\n encodeJson: (widenedConfig.encodeJson ?? identity) as (value: TInput) => JsonValue,\n decodeJson: (widenedConfig.decodeJson ?? identity) as (json: JsonValue) => TInput,\n } as Codec<Id, TTraits, TWire, TInput>;\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport { coreHash, profileHash } from '@prisma-next/contract/types';\nimport type {\n CodecDescriptor,\n CodecMeta,\n CodecTrait,\n} from '@prisma-next/framework-components/codec';\nimport {\n instantiateExecutionStack,\n type RuntimeDriverDescriptor,\n} from '@prisma-next/framework-components/execution';\nimport type { ResultType } from '@prisma-next/framework-components/runtime';\nimport { runtimeError } from '@prisma-next/framework-components/runtime';\nimport { canonicalizeJson } from '@prisma-next/framework-components/utils';\nimport { builtinGeneratorIds } from '@prisma-next/ids';\nimport { generateId } from '@prisma-next/ids/runtime';\nimport { SqlStorage, type SqlStorageInput } from '@prisma-next/sql-contract/types';\nimport type {\n Adapter,\n Codec,\n ContractCodecRegistry,\n LoweredStatement,\n SelectAst,\n} from '@prisma-next/sql-relational-core/ast';\nimport type { SqlExecutionPlan, SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';\nimport { collectAsync, drainAsyncIterable } from '@prisma-next/test-utils';\nimport type { Client } from 'pg';\nimport type { SqlStatement } from '../src/exports';\nimport {\n APP_SPACE_ID,\n createExecutionContext,\n type createRuntime,\n createSqlExecutionStack,\n ensureSchemaStatement,\n ensureTableStatement,\n writeContractMarker,\n} from '../src/exports';\nimport type {\n ExecutionContext,\n SqlRuntimeAdapterDescriptor,\n SqlRuntimeAdapterInstance,\n SqlRuntimeDriverInstance,\n SqlRuntimeExtensionDescriptor,\n SqlRuntimeTargetDescriptor,\n} from '../src/sql-context';\nimport { defineTestCodec } from './test-codec';\n\nfunction createTestMutationDefaultGenerators() {\n return builtinGeneratorIds.map((id) => ({\n id,\n generate: (params?: Record<string, unknown>) => generateId(params ? { id, params } : { id }),\n stability: 'field' as const,\n }));\n}\n\n/**\n * Executes a plan and collects all results into an array. This helper DRYs up the common pattern of executing plans in tests. The return type is inferred from the plan's type parameter.\n */\nexport async function executePlanAndCollect<\n P extends SqlExecutionPlan<ResultType<P>> | SqlQueryPlan<ResultType<P>>,\n>(runtime: ReturnType<typeof createRuntime>, plan: P): Promise<ResultType<P>[]> {\n type Row = ResultType<P>;\n return collectAsync<Row>(runtime.execute<Row>(plan));\n}\n\n/**\n * Drains a plan execution, consuming all results without collecting them. Useful for testing side effects without memory overhead.\n */\nexport async function drainPlanExecution(\n runtime: ReturnType<typeof createRuntime>,\n plan: SqlExecutionPlan | SqlQueryPlan<unknown>,\n): Promise<void> {\n return drainAsyncIterable(runtime.execute(plan));\n}\n\n/**\n * Executes a SQL statement on a database client.\n */\nexport async function executeStatement(client: Client, statement: SqlStatement): Promise<void> {\n if (statement.params.length > 0) {\n await client.query(statement.sql, [...statement.params]);\n return;\n }\n\n await client.query(statement.sql);\n}\n\n/**\n * Sets up database schema and data, then writes the contract marker. This helper DRYs up the common pattern of database setup in tests.\n */\nexport async function setupTestDatabase(\n client: Client,\n contract: Contract<SqlStorage>,\n setupFn: (client: Client) => Promise<void>,\n): Promise<void> {\n await client.query('drop schema if exists prisma_contract cascade');\n await client.query('create schema if not exists public');\n\n await setupFn(client);\n\n await executeStatement(client, ensureSchemaStatement);\n await executeStatement(client, ensureTableStatement);\n const write = writeContractMarker({\n space: APP_SPACE_ID,\n storageHash: contract.storage.storageHash,\n profileHash: contract.profileHash,\n contractJson: contract,\n canonicalVersion: 1,\n });\n await executeStatement(client, write.insert);\n}\n\n/**\n * Writes a contract marker to the database. This helper DRYs up the common pattern of writing contract markers in tests.\n */\nexport async function writeTestContractMarker(\n client: Client,\n contract: Contract<SqlStorage>,\n): Promise<void> {\n const write = writeContractMarker({\n space: APP_SPACE_ID,\n storageHash: contract.storage.storageHash,\n profileHash: contract.profileHash,\n contractJson: contract,\n canonicalVersion: 1,\n });\n await executeStatement(client, write.insert);\n}\n\n/**\n * Creates a test adapter descriptor from a raw adapter. Wraps the adapter in an SqlRuntimeAdapterDescriptor with static contributions derived from the adapter's codec registry.\n */\n/**\n * Build a {@link ContractCodecRegistry} from a codec array for tests that exercise `encodeParam(s)` / `decodeRow` in isolation. The production runtime builds `ContractCodecRegistry` from contract walk + descriptor list and never goes through this helper; tests use it to wire a hand-built codec set into the surface those functions consume in production.\n */\nexport function buildTestContractCodecs(\n codecs: ReadonlyArray<Codec<string>>,\n): ContractCodecRegistry {\n const byId = new Map<string, Codec<string>>();\n for (const codec of codecs) {\n byId.set(codec.id, codec);\n }\n // Canonical-key cache: production `forCodecRef` memoizes per `(codecId, canonicalize(typeParams))`. Tests resolve by codecId, but key the cache on the canonical pair so callers passing distinct typeParams get distinct (still codec-id-templated) entries — and so this helper cannot silently coalesce them.\n const byCanonicalKey = new Map<string, Codec<string>>();\n return {\n forColumn: () => undefined,\n forCodecRef: (ref) => {\n const canonicalKey = canonicalizeJson({\n codecId: ref.codecId,\n ...(ref.typeParams !== undefined ? { typeParams: ref.typeParams } : {}),\n });\n const cached = byCanonicalKey.get(canonicalKey);\n if (cached) return cached;\n const template = byId.get(ref.codecId);\n if (!template) {\n throw runtimeError(\n 'RUNTIME.CODEC_DESCRIPTOR_MISSING',\n `Test ContractCodecRegistry has no codec for codecId '${ref.codecId}'.`,\n {\n codecId: ref.codecId,\n ...(ref.typeParams !== undefined ? { typeParams: ref.typeParams } : {}),\n },\n );\n }\n byCanonicalKey.set(canonicalKey, template);\n return template;\n },\n };\n}\n\n/**\n * Synthesize `CodecDescriptor`s from a codec array of non-parameterized codec instances. Test-only: the production synthesis bridge was retired under TML-2357. Lets the existing `createTestAdapterDescriptor` pattern keep wrapping a stub `Adapter` (whose `__codecs` slot still exposes the codec set) into the descriptor-list shape that `SqlStaticContributions.codecs:` now expects. The `Codec` instances carry\n * `traits`/`targetTypes`/`meta` via the SQL family extension; the structural narrow reads those fields directly.\n */\nexport function descriptorsFromCodecs(\n codecs: ReadonlyArray<Codec<string>>,\n): ReadonlyArray<CodecDescriptor> {\n // Permissive paramsSchema for synthesized test descriptors: accepts any\n // shape (incl. undefined) and passes it through. Stubs do not encode\n // parameterization, so marking them `isParameterized: true` with this\n // schema lets the runtime integrity check tolerate columns that legitimately\n // carry typeParams (e.g. `sql/char@1` length=36) without re-introducing\n // the legacy \"non-parameterized + typeParams\" silent skip.\n // Permissive schema for synthesized test descriptors. `validate()` always\n // succeeds and discards input, narrowed to `void` to match the\n // `paramsSchema: StandardSchemaV1<void, void>` slot on the descriptor.\n // The factory ignores typeParams, so typing the validated output as `void`\n // is honest about what the stub does with the value.\n const acceptAnyParamsSchema = {\n '~standard': {\n version: 1 as const,\n vendor: 'sql-runtime/test-utils',\n validate: (_value: unknown) => ({ value: undefined }),\n },\n };\n const descriptors: CodecDescriptor[] = [];\n for (const instance of codecs) {\n const legacy = instance as {\n readonly traits?: readonly CodecTrait[];\n readonly targetTypes?: readonly string[];\n readonly meta?: CodecMeta;\n };\n descriptors.push({\n codecId: instance.id,\n traits: legacy.traits ?? [],\n targetTypes: legacy.targetTypes ?? [],\n paramsSchema: acceptAnyParamsSchema,\n isParameterized: true,\n factory: () => () => instance,\n ...(legacy.meta !== undefined ? { meta: legacy.meta } : {}),\n });\n }\n return descriptors;\n}\n\nexport function createTestAdapterDescriptor(\n adapter: StubAdapter,\n): SqlRuntimeAdapterDescriptor<'postgres'> {\n const descriptors = descriptorsFromCodecs(adapter.__codecs);\n return {\n kind: 'adapter' as const,\n id: 'test-adapter',\n version: '0.0.1',\n familyId: 'sql' as const,\n targetId: 'postgres' as const,\n codecs: () => descriptors,\n mutationDefaultGenerators: createTestMutationDefaultGenerators,\n create(_stack): SqlRuntimeAdapterInstance<'postgres'> {\n return Object.assign({ familyId: 'sql' as const, targetId: 'postgres' as const }, adapter);\n },\n };\n}\n\n/**\n * Creates a test target descriptor with empty static contributions.\n */\nexport function createTestTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {\n return {\n kind: 'target' as const,\n id: 'postgres',\n version: '0.0.1',\n familyId: 'sql' as const,\n targetId: 'postgres' as const,\n codecs: () => [],\n create() {\n return { familyId: 'sql' as const, targetId: 'postgres' as const };\n },\n };\n}\n\n/**\n * Creates an ExecutionContext for testing. This helper DRYs up the common pattern of context creation in tests.\n *\n * Accepts a raw adapter and optional extension descriptors, wrapping the adapter in a descriptor internally for descriptor-first context creation.\n */\nexport function createTestContext<TContract extends Contract<SqlStorage>>(\n contract: TContract,\n adapter: StubAdapter,\n options?: {\n extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;\n },\n): ExecutionContext<TContract> {\n return createExecutionContext({\n contract,\n stack: {\n target: createTestTargetDescriptor(),\n adapter: createTestAdapterDescriptor(adapter),\n extensionPacks: options?.extensionPacks ?? [],\n },\n });\n}\n\nexport function createTestStackInstance(options?: {\n extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;\n driver?: RuntimeDriverDescriptor<\n 'sql',\n 'postgres',\n unknown,\n SqlRuntimeDriverInstance<'postgres'>\n >;\n}) {\n const stack = createSqlExecutionStack({\n target: createTestTargetDescriptor(),\n adapter: createTestAdapterDescriptor(createStubAdapter()),\n driver: options?.driver,\n extensionPacks: options?.extensionPacks ?? [],\n });\n\n return instantiateExecutionStack(stack);\n}\n\n/**\n * Stub-adapter type augments the public {@link Adapter} surface with a `__codecs` slot that exposes the test stub's runtime codec set to descriptor-shaping helpers (`createTestAdapterDescriptor`). Production adapters do not declare this slot — runtime codecs flow through the descriptor list from `SqlRuntimeAdapterDescriptor.codecs()` — so the augmentation is intentionally test-only.\n */\nexport type StubAdapter = Adapter<SelectAst, Contract<SqlStorage>, LoweredStatement> & {\n readonly __codecs: ReadonlyArray<Codec<string>>;\n};\n\n/**\n * Creates a stub adapter for testing. This helper DRYs up the common pattern of adapter creation in tests.\n *\n * The stub adapter includes simple codecs for common test types (pg/int4@1, pg/text@1, pg/timestamptz@1) to enable type inference in tests without requiring the postgres adapter package.\n */\nexport function createStubAdapter(): StubAdapter {\n // Stub codecs for codec IDs that test contracts may reference. The set must\n // be complete enough to satisfy `assertColumnCodecIntegrity` against any\n // emitted test contract; the encode/decode bodies are passthrough since\n // the stub adapter never executes against a real driver.\n // The encode/decode bodies pass through; widen TInput to a JSON-safe type\n // so `defineTestCodec` does not require explicit JSON round-trip helpers.\n const passthroughCodec = (typeId: string, targetType: string): Codec<string> =>\n defineTestCodec({\n typeId,\n targetTypes: [targetType],\n encode: (value: string | number | boolean | null) => value,\n decode: (wire: string | number | boolean | null) => wire,\n });\n const codecs: ReadonlyArray<Codec<string>> = [\n passthroughCodec('pg/bit@1', 'bit'),\n passthroughCodec('pg/bool@1', 'bool'),\n passthroughCodec('pg/bytea@1', 'bytea'),\n passthroughCodec('pg/float4@1', 'float4'),\n passthroughCodec('pg/float8@1', 'float8'),\n passthroughCodec('pg/int2@1', 'int2'),\n defineTestCodec({\n typeId: 'pg/int4@1',\n targetTypes: ['int4'],\n encode: (value: number) => value,\n decode: (wire: number) => wire,\n }),\n passthroughCodec('pg/int8@1', 'int8'),\n passthroughCodec('pg/interval@1', 'interval'),\n passthroughCodec('pg/json@1', 'json'),\n passthroughCodec('pg/jsonb@1', 'jsonb'),\n passthroughCodec('pg/numeric@1', 'numeric'),\n defineTestCodec({\n typeId: 'pg/text@1',\n targetTypes: ['text'],\n encode: (value: string) => value,\n decode: (wire: string) => wire,\n }),\n passthroughCodec('pg/time@1', 'time'),\n defineTestCodec({\n typeId: 'pg/timestamp@1',\n targetTypes: ['timestamp'],\n encode: (value: Date) => value,\n decode: (wire: Date) => wire,\n encodeJson: (value: Date) => value.toISOString(),\n decodeJson: (json) => {\n if (typeof json !== 'string') throw new Error('expected ISO date string');\n return new Date(json);\n },\n }),\n defineTestCodec({\n typeId: 'pg/timestamptz@1',\n targetTypes: ['timestamptz'],\n encode: (value: Date) => value,\n decode: (wire: Date) => wire,\n // Date is not assignable to JsonValue, so the JSON round-trip pair must be supplied explicitly.\n encodeJson: (value: Date) => value.toISOString(),\n decodeJson: (json) => {\n if (typeof json !== 'string') throw new Error('expected ISO date string');\n return new Date(json);\n },\n }),\n passthroughCodec('pg/timetz@1', 'timetz'),\n passthroughCodec('pg/varbit@1', 'varbit'),\n passthroughCodec('pg/uuid@1', 'uuid'),\n passthroughCodec('sql/char@1', 'char'),\n passthroughCodec('sql/varchar@1', 'varchar'),\n ];\n\n return {\n __codecs: codecs,\n profile: {\n id: 'stub-profile',\n target: 'postgres',\n capabilities: {},\n readMarker: async () => ({ kind: 'absent' as const }),\n },\n lower(ast: SelectAst, ctx: { contract: Contract<SqlStorage>; params?: readonly unknown[] }) {\n const sqlText = JSON.stringify(ast);\n return Object.freeze({ sql: sqlText, params: ctx.params ? [...ctx.params] : [] });\n },\n };\n}\n\nexport function createTestContract(\n contract: Partial<Omit<Contract<SqlStorage>, 'profileHash' | 'storage'>> & {\n storageHash?: string;\n profileHash?: string;\n storage?: Omit<SqlStorageInput, 'storageHash'>;\n },\n): Contract<SqlStorage> {\n const { execution, ...rest } = contract;\n const storageHashValue = coreHash(rest['storageHash'] ?? 'sha256:testcore');\n\n return {\n target: rest['target'] ?? 'postgres',\n targetFamily: rest['targetFamily'] ?? 'sql',\n storage: rest['storage']\n ? new SqlStorage({ ...rest['storage'], storageHash: storageHashValue })\n : new SqlStorage({ storageHash: storageHashValue, tables: {} }),\n models: rest['models'] ?? {},\n roots: rest['roots'] ?? {},\n capabilities: rest['capabilities'] ?? {},\n extensionPacks: rest['extensionPacks'] ?? {},\n meta: rest['meta'] ?? {},\n ...(execution ? { execution } : {}),\n profileHash: profileHash(rest['profileHash'] ?? 'sha256:testprofile'),\n };\n}\n\n// Re-export generic utilities from test-utils\nexport {\n collectAsync,\n createDevDatabase,\n type DevDatabase,\n teardownTestDatabase,\n withClient,\n} from '@prisma-next/test-utils';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":["collectAsync","SelectAstCtor"],"sources":["../../test/test-codec.ts","../../test/utils.ts"],"sourcesContent":["/**\n * Test-only helper that constructs a SQL-family `Codec` instance from author-side encode/decode functions. Replaces the legacy public `mkCodec()` factory (deleted under TML-2357); tests that need a stub codec for behavioural assertions instantiate one through this helper rather than going through `descriptor.factory(...)`.\n *\n * The body is identical in spirit to the retired `mkCodec`: promise-lift sync author functions onto the framework-required `Promise<…>` boundary, default `encodeJson`/`decodeJson` to identity when `TInput` is JSON-safe, fail loudly otherwise.\n */\nimport type { JsonValue } from '@prisma-next/contract/types';\nimport type { CodecTrait } from '@prisma-next/framework-components/codec';\nimport type { Codec, SqlCodecCallContext } from '@prisma-next/sql-relational-core/ast';\n\ntype JsonRoundTripConfig<TInput> = [TInput] extends [JsonValue]\n ? {\n encodeJson?: (value: TInput) => JsonValue;\n decodeJson?: (json: JsonValue) => TInput;\n }\n : {\n encodeJson: (value: TInput) => JsonValue;\n decodeJson: (json: JsonValue) => TInput;\n };\n\nexport function defineTestCodec<\n Id extends string,\n const TTraits extends readonly CodecTrait[] = readonly [],\n TWire = unknown,\n TInput = unknown,\n>(\n config: {\n typeId: Id;\n targetTypes?: readonly string[];\n encode: (value: TInput, ctx: SqlCodecCallContext) => TWire | Promise<TWire>;\n decode: (wire: TWire, ctx: SqlCodecCallContext) => TInput | Promise<TInput>;\n traits?: TTraits;\n } & JsonRoundTripConfig<TInput>,\n): Codec<Id, TTraits, TWire, TInput> {\n const identity = (v: unknown) => v;\n const userEncode = config.encode;\n const userDecode = config.decode;\n const widenedConfig = config as {\n encodeJson?: (value: TInput) => JsonValue;\n decodeJson?: (json: JsonValue) => TInput;\n };\n return {\n id: config.typeId,\n encode: (value, ctx) => {\n try {\n return Promise.resolve(userEncode(value, ctx));\n } catch (error) {\n return Promise.reject(error);\n }\n },\n decode: (wire, ctx) => {\n try {\n return Promise.resolve(userDecode(wire, ctx));\n } catch (error) {\n return Promise.reject(error);\n }\n },\n encodeJson: (widenedConfig.encodeJson ?? identity) as (value: TInput) => JsonValue,\n decodeJson: (widenedConfig.decodeJson ?? identity) as (json: JsonValue) => TInput,\n } as Codec<Id, TTraits, TWire, TInput>;\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport { coreHash, profileHash } from '@prisma-next/contract/types';\nimport type {\n CodecDescriptor,\n CodecMeta,\n CodecTrait,\n} from '@prisma-next/framework-components/codec';\nimport {\n instantiateExecutionStack,\n type RuntimeDriverDescriptor,\n} from '@prisma-next/framework-components/execution';\nimport type { ResultType } from '@prisma-next/framework-components/runtime';\nimport { runtimeError } from '@prisma-next/framework-components/runtime';\nimport { canonicalizeJson } from '@prisma-next/framework-components/utils';\nimport { builtinGeneratorIds } from '@prisma-next/ids';\nimport { generateId } from '@prisma-next/ids/runtime';\nimport { SqlStorage, type SqlStorageInput } from '@prisma-next/sql-contract/types';\nimport type {\n Adapter,\n AnyQueryAst,\n Codec,\n ContractCodecRegistry,\n LoweredStatement,\n SelectAst,\n} from '@prisma-next/sql-relational-core/ast';\nimport { SelectAst as SelectAstCtor, TableSource } from '@prisma-next/sql-relational-core/ast';\nimport type { SqlExecutionPlan, SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';\nimport { collectAsync, drainAsyncIterable } from '@prisma-next/test-utils';\nimport type { Client } from 'pg';\nimport type { SqlStatement } from '../src/exports';\nimport {\n APP_SPACE_ID,\n createExecutionContext,\n type createRuntime,\n createSqlExecutionStack,\n ensureSchemaStatement,\n ensureTableStatement,\n writeContractMarker,\n} from '../src/exports';\nimport type {\n ExecutionContext,\n SqlRuntimeAdapterDescriptor,\n SqlRuntimeAdapterInstance,\n SqlRuntimeDriverInstance,\n SqlRuntimeExtensionDescriptor,\n SqlRuntimeTargetDescriptor,\n} from '../src/sql-context';\nimport { defineTestCodec } from './test-codec';\n\nfunction createTestMutationDefaultGenerators() {\n return builtinGeneratorIds.map((id) => ({\n id,\n generate: (params?: Record<string, unknown>) => generateId(params ? { id, params } : { id }),\n stability: 'field' as const,\n }));\n}\n\n/**\n * Executes a plan and collects all results into an array. This helper DRYs up the common pattern of executing plans in tests. The return type is inferred from the plan's type parameter.\n */\nexport async function executePlanAndCollect<\n P extends SqlExecutionPlan<ResultType<P>> | SqlQueryPlan<ResultType<P>>,\n>(runtime: ReturnType<typeof createRuntime>, plan: P): Promise<ResultType<P>[]> {\n type Row = ResultType<P>;\n return collectAsync<Row>(runtime.execute<Row>(plan));\n}\n\n/**\n * Drains a plan execution, consuming all results without collecting them. Useful for testing side effects without memory overhead.\n */\nexport async function drainPlanExecution(\n runtime: ReturnType<typeof createRuntime>,\n plan: SqlExecutionPlan | SqlQueryPlan<unknown>,\n): Promise<void> {\n return drainAsyncIterable(runtime.execute(plan));\n}\n\n/**\n * Executes a SQL statement on a database client.\n */\nexport async function executeStatement(client: Client, statement: SqlStatement): Promise<void> {\n if (statement.params.length > 0) {\n await client.query(statement.sql, [...statement.params]);\n return;\n }\n\n await client.query(statement.sql);\n}\n\n/**\n * Sets up database schema and data, then writes the contract marker. This helper DRYs up the common pattern of database setup in tests.\n */\nexport async function setupTestDatabase(\n client: Client,\n contract: Contract<SqlStorage>,\n setupFn: (client: Client) => Promise<void>,\n): Promise<void> {\n await client.query('drop schema if exists prisma_contract cascade');\n await client.query('create schema if not exists public');\n\n await setupFn(client);\n\n await executeStatement(client, ensureSchemaStatement);\n await executeStatement(client, ensureTableStatement);\n const write = writeContractMarker({\n space: APP_SPACE_ID,\n storageHash: contract.storage.storageHash,\n profileHash: contract.profileHash,\n contractJson: contract,\n canonicalVersion: 1,\n });\n await executeStatement(client, write.insert);\n}\n\n/**\n * Writes a contract marker to the database. This helper DRYs up the common pattern of writing contract markers in tests.\n */\nexport async function writeTestContractMarker(\n client: Client,\n contract: Contract<SqlStorage>,\n): Promise<void> {\n const write = writeContractMarker({\n space: APP_SPACE_ID,\n storageHash: contract.storage.storageHash,\n profileHash: contract.profileHash,\n contractJson: contract,\n canonicalVersion: 1,\n });\n await executeStatement(client, write.insert);\n}\n\n/**\n * Creates a test adapter descriptor from a raw adapter. Wraps the adapter in an SqlRuntimeAdapterDescriptor with static contributions derived from the adapter's codec registry.\n */\n/**\n * Build a {@link ContractCodecRegistry} from a codec array for tests that exercise `encodeParam(s)` / `decodeRow` in isolation. The production runtime builds `ContractCodecRegistry` from contract walk + descriptor list and never goes through this helper; tests use it to wire a hand-built codec set into the surface those functions consume in production.\n */\nexport function buildTestContractCodecs(\n codecs: ReadonlyArray<Codec<string>>,\n): ContractCodecRegistry {\n const byId = new Map<string, Codec<string>>();\n for (const codec of codecs) {\n byId.set(codec.id, codec);\n }\n // Canonical-key cache: production `forCodecRef` memoizes per `(codecId, canonicalize(typeParams))`. Tests resolve by codecId, but key the cache on the canonical pair so callers passing distinct typeParams get distinct (still codec-id-templated) entries — and so this helper cannot silently coalesce them.\n const byCanonicalKey = new Map<string, Codec<string>>();\n return {\n forColumn: () => undefined,\n forCodecRef: (ref) => {\n const canonicalKey = canonicalizeJson({\n codecId: ref.codecId,\n ...(ref.typeParams !== undefined ? { typeParams: ref.typeParams } : {}),\n });\n const cached = byCanonicalKey.get(canonicalKey);\n if (cached) return cached;\n const template = byId.get(ref.codecId);\n if (!template) {\n throw runtimeError(\n 'RUNTIME.CODEC_DESCRIPTOR_MISSING',\n `Test ContractCodecRegistry has no codec for codecId '${ref.codecId}'.`,\n {\n codecId: ref.codecId,\n ...(ref.typeParams !== undefined ? { typeParams: ref.typeParams } : {}),\n },\n );\n }\n byCanonicalKey.set(canonicalKey, template);\n return template;\n },\n };\n}\n\n/**\n * Synthesize `CodecDescriptor`s from a codec array of non-parameterized codec instances. Test-only: the production synthesis bridge was retired under TML-2357. Lets the existing `createTestAdapterDescriptor` pattern keep wrapping a stub `Adapter` (whose `__codecs` slot still exposes the codec set) into the descriptor-list shape that `SqlStaticContributions.codecs:` now expects. The `Codec` instances carry\n * `traits`/`targetTypes`/`meta` via the SQL family extension; the structural narrow reads those fields directly.\n */\nexport function descriptorsFromCodecs(\n codecs: ReadonlyArray<Codec<string>>,\n): ReadonlyArray<CodecDescriptor> {\n // Permissive paramsSchema for synthesized test descriptors: accepts any\n // shape (incl. undefined) and passes it through. Stubs do not encode\n // parameterization, so marking them `isParameterized: true` with this\n // schema lets the runtime integrity check tolerate columns that legitimately\n // carry typeParams (e.g. `sql/char@1` length=36) without re-introducing\n // the legacy \"non-parameterized + typeParams\" silent skip.\n // Permissive schema for synthesized test descriptors. `validate()` always\n // succeeds and discards input, narrowed to `void` to match the\n // `paramsSchema: StandardSchemaV1<void, void>` slot on the descriptor.\n // The factory ignores typeParams, so typing the validated output as `void`\n // is honest about what the stub does with the value.\n const acceptAnyParamsSchema = {\n '~standard': {\n version: 1 as const,\n vendor: 'sql-runtime/test-utils',\n validate: (_value: unknown) => ({ value: undefined }),\n },\n };\n const descriptors: CodecDescriptor[] = [];\n for (const instance of codecs) {\n const legacy = instance as {\n readonly traits?: readonly CodecTrait[];\n readonly targetTypes?: readonly string[];\n readonly meta?: CodecMeta;\n };\n descriptors.push({\n codecId: instance.id,\n traits: legacy.traits ?? [],\n targetTypes: legacy.targetTypes ?? [],\n paramsSchema: acceptAnyParamsSchema,\n isParameterized: true,\n factory: () => () => instance,\n ...(legacy.meta !== undefined ? { meta: legacy.meta } : {}),\n });\n }\n return descriptors;\n}\n\nexport function createTestAdapterDescriptor(\n adapter: StubAdapter,\n): SqlRuntimeAdapterDescriptor<'postgres'> {\n const descriptors = descriptorsFromCodecs(adapter.__codecs);\n return {\n kind: 'adapter' as const,\n id: 'test-adapter',\n version: '0.0.1',\n familyId: 'sql' as const,\n targetId: 'postgres' as const,\n codecs: () => descriptors,\n mutationDefaultGenerators: createTestMutationDefaultGenerators,\n create(_stack): SqlRuntimeAdapterInstance<'postgres'> {\n return Object.assign({ familyId: 'sql' as const, targetId: 'postgres' as const }, adapter);\n },\n };\n}\n\n/**\n * Creates a test target descriptor with empty static contributions.\n */\nexport function createTestTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {\n return {\n kind: 'target' as const,\n id: 'postgres',\n version: '0.0.1',\n familyId: 'sql' as const,\n targetId: 'postgres' as const,\n codecs: () => [],\n create() {\n return { familyId: 'sql' as const, targetId: 'postgres' as const };\n },\n };\n}\n\n/**\n * Creates an ExecutionContext for testing. This helper DRYs up the common pattern of context creation in tests.\n *\n * Accepts a raw adapter and optional extension descriptors, wrapping the adapter in a descriptor internally for descriptor-first context creation.\n */\nexport function createTestContext<TContract extends Contract<SqlStorage>>(\n contract: TContract,\n adapter: StubAdapter,\n options?: {\n extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;\n },\n): ExecutionContext<TContract> {\n return createExecutionContext({\n contract,\n stack: {\n target: createTestTargetDescriptor(),\n adapter: createTestAdapterDescriptor(adapter),\n extensionPacks: options?.extensionPacks ?? [],\n },\n });\n}\n\nexport function createTestStackInstance(options?: {\n extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;\n driver?: RuntimeDriverDescriptor<\n 'sql',\n 'postgres',\n unknown,\n SqlRuntimeDriverInstance<'postgres'>\n >;\n}) {\n const stack = createSqlExecutionStack({\n target: createTestTargetDescriptor(),\n adapter: createTestAdapterDescriptor(createStubAdapter()),\n driver: options?.driver,\n extensionPacks: options?.extensionPacks ?? [],\n });\n\n return instantiateExecutionStack(stack);\n}\n\n/**\n * Stub-adapter type augments the public {@link Adapter} surface with a `__codecs` slot that exposes the test stub's runtime codec set to descriptor-shaping helpers (`createTestAdapterDescriptor`). Production adapters do not declare this slot — runtime codecs flow through the descriptor list from `SqlRuntimeAdapterDescriptor.codecs()` — so the augmentation is intentionally test-only.\n */\nexport type StubAdapter = Adapter<SelectAst, Contract<SqlStorage>, LoweredStatement> & {\n readonly __codecs: ReadonlyArray<Codec<string>>;\n};\n\n/**\n * Creates a stub adapter for testing. This helper DRYs up the common pattern of adapter creation in tests.\n *\n * The stub adapter includes simple codecs for common test types (pg/int4@1, pg/text@1, pg/timestamptz@1) to enable type inference in tests without requiring the postgres adapter package.\n */\nexport function createStubAdapter(): StubAdapter {\n // Stub codecs for codec IDs that test contracts may reference. The set must\n // be complete enough to satisfy `assertColumnCodecIntegrity` against any\n // emitted test contract; the encode/decode bodies are passthrough since\n // the stub adapter never executes against a real driver.\n // The encode/decode bodies pass through; widen TInput to a JSON-safe type\n // so `defineTestCodec` does not require explicit JSON round-trip helpers.\n const passthroughCodec = (typeId: string, targetType: string): Codec<string> =>\n defineTestCodec({\n typeId,\n targetTypes: [targetType],\n encode: (value: string | number | boolean | null) => value,\n decode: (wire: string | number | boolean | null) => wire,\n });\n const codecs: ReadonlyArray<Codec<string>> = [\n passthroughCodec('pg/bit@1', 'bit'),\n passthroughCodec('pg/bool@1', 'bool'),\n passthroughCodec('pg/bytea@1', 'bytea'),\n passthroughCodec('pg/float4@1', 'float4'),\n passthroughCodec('pg/float8@1', 'float8'),\n passthroughCodec('pg/int2@1', 'int2'),\n defineTestCodec({\n typeId: 'pg/int4@1',\n targetTypes: ['int4'],\n encode: (value: number) => value,\n decode: (wire: number) => wire,\n }),\n passthroughCodec('pg/int8@1', 'int8'),\n passthroughCodec('pg/interval@1', 'interval'),\n passthroughCodec('pg/json@1', 'json'),\n passthroughCodec('pg/jsonb@1', 'jsonb'),\n passthroughCodec('pg/numeric@1', 'numeric'),\n defineTestCodec({\n typeId: 'pg/text@1',\n targetTypes: ['text'],\n encode: (value: string) => value,\n decode: (wire: string) => wire,\n }),\n passthroughCodec('pg/time@1', 'time'),\n defineTestCodec({\n typeId: 'pg/timestamp@1',\n targetTypes: ['timestamp'],\n encode: (value: Date) => value,\n decode: (wire: Date) => wire,\n encodeJson: (value: Date) => value.toISOString(),\n decodeJson: (json) => {\n if (typeof json !== 'string') throw new Error('expected ISO date string');\n return new Date(json);\n },\n }),\n defineTestCodec({\n typeId: 'pg/timestamptz@1',\n targetTypes: ['timestamptz'],\n encode: (value: Date) => value,\n decode: (wire: Date) => wire,\n // Date is not assignable to JsonValue, so the JSON round-trip pair must be supplied explicitly.\n encodeJson: (value: Date) => value.toISOString(),\n decodeJson: (json) => {\n if (typeof json !== 'string') throw new Error('expected ISO date string');\n return new Date(json);\n },\n }),\n passthroughCodec('pg/timetz@1', 'timetz'),\n passthroughCodec('pg/varbit@1', 'varbit'),\n passthroughCodec('pg/uuid@1', 'uuid'),\n passthroughCodec('sql/char@1', 'char'),\n passthroughCodec('sql/varchar@1', 'varchar'),\n ];\n\n return {\n __codecs: codecs,\n profile: {\n id: 'stub-profile',\n target: 'postgres',\n capabilities: {},\n readMarker: async () => ({ kind: 'absent' as const }),\n },\n lower(ast: SelectAst, _ctx: { contract: Contract<SqlStorage>; params?: readonly unknown[] }) {\n const sqlText = JSON.stringify(ast);\n const refs = ast.collectParamRefs();\n const params = refs.map((ref) =>\n ref.kind === 'prepared-param-ref'\n ? ({ kind: 'bind' as const, name: ref.name } as const)\n : ({ kind: 'literal' as const, value: ref.value } as const),\n );\n return Object.freeze({ sql: sqlText, params });\n },\n };\n}\n\nexport function createTestContract(\n contract: Partial<Omit<Contract<SqlStorage>, 'profileHash' | 'storage'>> & {\n storageHash?: string;\n profileHash?: string;\n storage?: Omit<SqlStorageInput, 'storageHash'>;\n },\n): Contract<SqlStorage> {\n const { execution, ...rest } = contract;\n const storageHashValue = coreHash(rest['storageHash'] ?? 'sha256:testcore');\n\n return {\n target: rest['target'] ?? 'postgres',\n targetFamily: rest['targetFamily'] ?? 'sql',\n storage: rest['storage']\n ? new SqlStorage({ ...rest['storage'], storageHash: storageHashValue })\n : new SqlStorage({ storageHash: storageHashValue, tables: {} }),\n models: rest['models'] ?? {},\n roots: rest['roots'] ?? {},\n capabilities: rest['capabilities'] ?? {},\n extensionPacks: rest['extensionPacks'] ?? {},\n meta: rest['meta'] ?? {},\n ...(execution ? { execution } : {}),\n profileHash: profileHash(rest['profileHash'] ?? 'sha256:testprofile'),\n };\n}\n\nexport function stubAst(): AnyQueryAst {\n return SelectAstCtor.from(TableSource.named('stub'));\n}\n\n// Re-export generic utilities from test-utils\nexport {\n collectAsync,\n createDevDatabase,\n type DevDatabase,\n teardownTestDatabase,\n withClient,\n} from '@prisma-next/test-utils';\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-runtime",
|
|
3
|
-
"version": "0.9.0-dev.
|
|
3
|
+
"version": "0.9.0-dev.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "SQL runtime implementation for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/contract": "0.9.0-dev.
|
|
10
|
-
"@prisma-next/utils": "0.9.0-dev.
|
|
11
|
-
"@prisma-next/framework-components": "0.9.0-dev.
|
|
12
|
-
"@prisma-next/ids": "0.9.0-dev.
|
|
13
|
-
"@prisma-next/operations": "0.9.0-dev.
|
|
14
|
-
"@prisma-next/sql-contract": "0.9.0-dev.
|
|
15
|
-
"@prisma-next/sql-operations": "0.9.0-dev.
|
|
16
|
-
"@prisma-next/sql-relational-core": "0.9.0-dev.
|
|
9
|
+
"@prisma-next/contract": "0.9.0-dev.3",
|
|
10
|
+
"@prisma-next/utils": "0.9.0-dev.3",
|
|
11
|
+
"@prisma-next/framework-components": "0.9.0-dev.3",
|
|
12
|
+
"@prisma-next/ids": "0.9.0-dev.3",
|
|
13
|
+
"@prisma-next/operations": "0.9.0-dev.3",
|
|
14
|
+
"@prisma-next/sql-contract": "0.9.0-dev.3",
|
|
15
|
+
"@prisma-next/sql-operations": "0.9.0-dev.3",
|
|
16
|
+
"@prisma-next/sql-relational-core": "0.9.0-dev.3",
|
|
17
17
|
"arktype": "^2.1.29"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@prisma-next/test-utils": "0.9.0-dev.
|
|
21
|
-
"@prisma-next/tsconfig": "0.9.0-dev.
|
|
20
|
+
"@prisma-next/test-utils": "0.9.0-dev.3",
|
|
21
|
+
"@prisma-next/tsconfig": "0.9.0-dev.3",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.20.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.9.0-dev.
|
|
24
|
+
"@prisma-next/tsdown": "0.9.0-dev.3",
|
|
25
25
|
"tsdown": "0.22.0",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.5"
|
package/src/codecs/decoding.ts
CHANGED
|
@@ -11,11 +11,10 @@ import type {
|
|
|
11
11
|
ProjectionItem,
|
|
12
12
|
SqlCodecCallContext,
|
|
13
13
|
} from '@prisma-next/sql-relational-core/ast';
|
|
14
|
-
import type { SqlExecutionPlan } from '@prisma-next/sql-relational-core/plan';
|
|
15
14
|
|
|
16
15
|
type ColumnRef = { table: string; column: string };
|
|
17
16
|
|
|
18
|
-
interface DecodeContext {
|
|
17
|
+
export interface DecodeContext {
|
|
19
18
|
readonly aliases: ReadonlyArray<string> | undefined;
|
|
20
19
|
readonly codecs: ReadonlyMap<string, Codec>;
|
|
21
20
|
readonly columnRefs: ReadonlyMap<string, ColumnRef>;
|
|
@@ -25,12 +24,6 @@ interface DecodeContext {
|
|
|
25
24
|
const WIRE_PREVIEW_LIMIT = 100;
|
|
26
25
|
const EMPTY_INCLUDE_ALIASES: ReadonlySet<string> = new Set<string>();
|
|
27
26
|
|
|
28
|
-
function isAstBackedPlan(
|
|
29
|
-
plan: SqlExecutionPlan,
|
|
30
|
-
): plan is SqlExecutionPlan & { readonly ast: AnyQueryAst } {
|
|
31
|
-
return plan.ast !== undefined;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
27
|
function projectionListFromAst(ast: AnyQueryAst): ReadonlyArray<ProjectionItem> | undefined {
|
|
35
28
|
if (ast.kind === 'select') {
|
|
36
29
|
return ast.projection;
|
|
@@ -51,21 +44,12 @@ function resolveProjectionCodec(
|
|
|
51
44
|
return undefined;
|
|
52
45
|
}
|
|
53
46
|
|
|
54
|
-
function buildDecodeContext(
|
|
55
|
-
|
|
47
|
+
export function buildDecodeContext(
|
|
48
|
+
ast: AnyQueryAst,
|
|
56
49
|
contractCodecs: ContractCodecRegistry | undefined,
|
|
57
50
|
): DecodeContext {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
aliases: undefined,
|
|
61
|
-
codecs: new Map(),
|
|
62
|
-
columnRefs: new Map(),
|
|
63
|
-
includeAliases: EMPTY_INCLUDE_ALIASES,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const projection = projectionListFromAst(plan.ast);
|
|
68
|
-
if (!projection) {
|
|
51
|
+
const projection = projectionListFromAst(ast);
|
|
52
|
+
if (!projection || projection.length === 0) {
|
|
69
53
|
return {
|
|
70
54
|
aliases: undefined,
|
|
71
55
|
codecs: new Map(),
|
|
@@ -223,15 +207,12 @@ async function decodeField(
|
|
|
223
207
|
*/
|
|
224
208
|
export async function decodeRow(
|
|
225
209
|
row: Record<string, unknown>,
|
|
226
|
-
|
|
210
|
+
decodeCtx: DecodeContext,
|
|
227
211
|
rowCtx: SqlCodecCallContext,
|
|
228
|
-
contractCodecs?: ContractCodecRegistry,
|
|
229
212
|
): Promise<Record<string, unknown>> {
|
|
230
213
|
checkAborted(rowCtx, 'decode');
|
|
231
214
|
const signal = rowCtx.signal;
|
|
232
215
|
|
|
233
|
-
const decodeCtx = buildDecodeContext(plan, contractCodecs);
|
|
234
|
-
|
|
235
216
|
const aliases = decodeCtx.aliases ?? Object.keys(row);
|
|
236
217
|
|
|
237
218
|
if (decodeCtx.aliases !== undefined) {
|
package/src/codecs/encoding.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
runtimeError,
|
|
6
6
|
} from '@prisma-next/framework-components/runtime';
|
|
7
7
|
import {
|
|
8
|
+
type AnyQueryAst,
|
|
8
9
|
type Codec,
|
|
9
10
|
type CodecRef,
|
|
10
11
|
type ContractCodecRegistry,
|
|
@@ -13,7 +14,7 @@ import {
|
|
|
13
14
|
} from '@prisma-next/sql-relational-core/ast';
|
|
14
15
|
import type { SqlExecutionPlan } from '@prisma-next/sql-relational-core/plan';
|
|
15
16
|
|
|
16
|
-
interface ParamMetadata {
|
|
17
|
+
export interface ParamMetadata {
|
|
17
18
|
readonly codec: CodecRef | undefined;
|
|
18
19
|
readonly name: string | undefined;
|
|
19
20
|
}
|
|
@@ -23,6 +24,19 @@ const NO_METADATA: ParamMetadata = Object.freeze({
|
|
|
23
24
|
name: undefined,
|
|
24
25
|
});
|
|
25
26
|
|
|
27
|
+
// Indexed by Postgres-style deduped slot order (matches the adapter's
|
|
28
|
+
// `collectOrderedParamRefs` walk). For SQLite's non-deduped renderer,
|
|
29
|
+
// `lowered.params` has one entry per occurrence: positions past
|
|
30
|
+
// `refs.length` fall back to `NO_METADATA` in encodeParamsWithMetadata,
|
|
31
|
+
// so codec'd repeats round-trip unchanged — a limitation that will be
|
|
32
|
+
// revisited when SQLite prepared statements ship and each adapter
|
|
33
|
+
// carries codec metadata on its `LoweredParam` slots directly.
|
|
34
|
+
export function deriveParamMetadata(ast: AnyQueryAst): readonly ParamMetadata[] {
|
|
35
|
+
return collectOrderedParamRefs(ast).map((ref): ParamMetadata => {
|
|
36
|
+
return { codec: ref.codec, name: ref.name };
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
function resolveParamCodec(
|
|
27
41
|
metadata: ParamMetadata,
|
|
28
42
|
contractCodecs: ContractCodecRegistry | undefined,
|
|
@@ -122,31 +136,26 @@ export async function encodeParams(
|
|
|
122
136
|
plan: SqlExecutionPlan,
|
|
123
137
|
ctx: SqlCodecCallContext,
|
|
124
138
|
contractCodecs?: ContractCodecRegistry,
|
|
139
|
+
): Promise<readonly unknown[]> {
|
|
140
|
+
return encodeParamsWithMetadata(plan.params, deriveParamMetadata(plan.ast), ctx, contractCodecs);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export async function encodeParamsWithMetadata(
|
|
144
|
+
values: readonly unknown[],
|
|
145
|
+
metadata: readonly ParamMetadata[],
|
|
146
|
+
ctx: SqlCodecCallContext,
|
|
147
|
+
contractCodecs?: ContractCodecRegistry,
|
|
125
148
|
): Promise<readonly unknown[]> {
|
|
126
149
|
checkAborted(ctx, 'encode');
|
|
127
150
|
const signal = ctx.signal;
|
|
128
151
|
|
|
129
|
-
if (
|
|
130
|
-
return
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const paramCount = plan.params.length;
|
|
134
|
-
const metadata: ParamMetadata[] = new Array(paramCount).fill(NO_METADATA);
|
|
135
|
-
|
|
136
|
-
if (plan.ast) {
|
|
137
|
-
const refs = collectOrderedParamRefs(plan.ast);
|
|
138
|
-
for (let i = 0; i < paramCount && i < refs.length; i++) {
|
|
139
|
-
const ref = refs[i];
|
|
140
|
-
if (ref) {
|
|
141
|
-
metadata[i] = { codec: ref.codec, name: ref.name };
|
|
142
|
-
}
|
|
143
|
-
}
|
|
152
|
+
if (values.length === 0) {
|
|
153
|
+
return values;
|
|
144
154
|
}
|
|
145
155
|
|
|
146
|
-
const tasks
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
156
|
+
const tasks = values.map((value, i) =>
|
|
157
|
+
encodeParamValue(value, metadata[i] ?? NO_METADATA, i, ctx, contractCodecs),
|
|
158
|
+
);
|
|
150
159
|
|
|
151
160
|
const settled = await raceAgainstAbort(Promise.all(tasks), signal, 'encode');
|
|
152
161
|
return Object.freeze(settled);
|
package/src/exports/index.ts
CHANGED
|
@@ -15,6 +15,16 @@ export { budgets } from '../middleware/budgets';
|
|
|
15
15
|
export type { LintsOptions } from '../middleware/lints';
|
|
16
16
|
export { lints } from '../middleware/lints';
|
|
17
17
|
export type { SqlMiddleware, SqlMiddlewareContext } from '../middleware/sql-middleware';
|
|
18
|
+
export type {
|
|
19
|
+
BindSiteParams,
|
|
20
|
+
Declaration,
|
|
21
|
+
DeclaredCodecId,
|
|
22
|
+
DeclaredNullable,
|
|
23
|
+
ParamSpec,
|
|
24
|
+
ParamsFromDeclaration,
|
|
25
|
+
PrepareCallback,
|
|
26
|
+
PreparedStatement,
|
|
27
|
+
} from '../prepared/types';
|
|
18
28
|
export type {
|
|
19
29
|
MarkerReader,
|
|
20
30
|
RuntimeFamilyAdapter,
|
package/src/lower-sql-plan.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
|
+
import { runtimeError } from '@prisma-next/framework-components/runtime';
|
|
2
3
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
3
4
|
import type { Adapter, AnyQueryAst, LoweredStatement } from '@prisma-next/sql-relational-core/ast';
|
|
4
5
|
import type { SqlExecutionPlan, SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
|
|
@@ -6,10 +7,11 @@ import type { SqlExecutionPlan, SqlQueryPlan } from '@prisma-next/sql-relational
|
|
|
6
7
|
/**
|
|
7
8
|
* Lowers a SQL query plan to an executable Plan by calling the adapter's lower method.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Ad-hoc lowerings produce only `{kind: 'literal'}` slots; this helper
|
|
11
|
+
* unwraps them into the bare-value array `SqlExecutionPlan` exposes.
|
|
12
|
+
* Encountering a `{kind: 'bind'}` slot here means the caller passed an
|
|
13
|
+
* AST containing `PreparedParamRef` to the ad-hoc execute path — that's a
|
|
14
|
+
* caller error, surfaced as `RUNTIME.PREPARE_BIND_ON_ADHOC`.
|
|
13
15
|
*/
|
|
14
16
|
export function lowerSqlPlan<Row>(
|
|
15
17
|
adapter: Adapter<AnyQueryAst, Contract<SqlStorage>, LoweredStatement>,
|
|
@@ -21,9 +23,18 @@ export function lowerSqlPlan<Row>(
|
|
|
21
23
|
params: queryPlan.params,
|
|
22
24
|
});
|
|
23
25
|
|
|
26
|
+
const params: unknown[] = lowered.params.map((slot) => {
|
|
27
|
+
if (slot.kind === 'literal') return slot.value;
|
|
28
|
+
throw runtimeError(
|
|
29
|
+
'RUNTIME.PREPARE_BIND_ON_ADHOC',
|
|
30
|
+
`Ad-hoc execute received a bind-site slot for '${slot.name}' — bind-site references are only valid inside runtime.prepare(...).`,
|
|
31
|
+
{ name: slot.name },
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
24
35
|
return Object.freeze({
|
|
25
36
|
sql: lowered.sql,
|
|
26
|
-
params
|
|
37
|
+
params,
|
|
27
38
|
ast: queryPlan.ast,
|
|
28
39
|
meta: queryPlan.meta,
|
|
29
40
|
});
|
|
@@ -51,10 +51,13 @@ function estimateRowsFromAst(
|
|
|
51
51
|
|
|
52
52
|
const tableEstimate = tableRows[primaryTableFromAst(ast)] ?? defaultTableRows;
|
|
53
53
|
|
|
54
|
-
if (ast.limit
|
|
54
|
+
if (typeof ast.limit === 'number') {
|
|
55
55
|
return Math.min(ast.limit, tableEstimate);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
// Expression-form limit: value is dynamic at execute time (e.g. a prepared
|
|
59
|
+
// bind site). Treat as bounded but unknown — the table estimate is the
|
|
60
|
+
// worst case.
|
|
58
61
|
return tableEstimate;
|
|
59
62
|
}
|
|
60
63
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyExpression as AstExpression,
|
|
3
|
+
CodecRef,
|
|
4
|
+
} from '@prisma-next/sql-relational-core/ast';
|
|
5
|
+
import { PreparedParamRef } from '@prisma-next/sql-relational-core/ast';
|
|
6
|
+
import type { Expression, ScopeField } from '@prisma-next/sql-relational-core/expression';
|
|
7
|
+
import type { BindSiteParams, Declaration, ParamSpec } from './types';
|
|
8
|
+
|
|
9
|
+
function normalizeSpec(spec: ParamSpec): { codec: CodecRef; nullable: boolean } {
|
|
10
|
+
if (typeof spec === 'string') return { codec: { codecId: spec }, nullable: false };
|
|
11
|
+
const codec: CodecRef =
|
|
12
|
+
spec.typeParams !== undefined
|
|
13
|
+
? { codecId: spec.codecId, typeParams: spec.typeParams }
|
|
14
|
+
: { codecId: spec.codecId };
|
|
15
|
+
return { codec, nullable: spec.nullable === true };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class BindSiteExpression implements Expression<ScopeField> {
|
|
19
|
+
readonly returnType: ScopeField;
|
|
20
|
+
readonly #ast: AstExpression;
|
|
21
|
+
constructor(ref: PreparedParamRef, returnType: ScopeField) {
|
|
22
|
+
this.#ast = ref;
|
|
23
|
+
this.returnType = returnType;
|
|
24
|
+
}
|
|
25
|
+
buildAst(): AstExpression {
|
|
26
|
+
return this.#ast;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function buildBindSiteParams<D extends Declaration>(declaration: D): BindSiteParams<D> {
|
|
31
|
+
const params: Record<string, Expression<ScopeField>> = {};
|
|
32
|
+
for (const [name, spec] of Object.entries(declaration)) {
|
|
33
|
+
const { codec, nullable } = normalizeSpec(spec);
|
|
34
|
+
const ref = PreparedParamRef.of(name, codec);
|
|
35
|
+
params[name] = new BindSiteExpression(ref, { codecId: codec.codecId, nullable });
|
|
36
|
+
}
|
|
37
|
+
// The cast narrows the structurally-equivalent record to the per-key
|
|
38
|
+
// codecId/nullable types declared by D — TypeScript can't relate the
|
|
39
|
+
// mapped-type keys to the runtime keys without reflection.
|
|
40
|
+
return Object.freeze(params) as BindSiteParams<D>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { runtimeError } from '@prisma-next/framework-components/runtime';
|
|
2
|
+
import type {
|
|
3
|
+
ContractCodecRegistry,
|
|
4
|
+
SqlCodecCallContext,
|
|
5
|
+
} from '@prisma-next/sql-relational-core/ast';
|
|
6
|
+
import { encodeParamsWithMetadata } from '../codecs/encoding';
|
|
7
|
+
import type { PreparedStatementInternals } from './prepared-statement';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a PreparedStatement's slot order to the unencoded values it
|
|
11
|
+
* will carry into encode. Literal slots come from the lowered AST;
|
|
12
|
+
* bind slots are looked up by name on `userParams`. Missing user params
|
|
13
|
+
* surface `RUNTIME.PREPARE_MISSING_PARAM` so the caller cannot silently
|
|
14
|
+
* bind `undefined`.
|
|
15
|
+
*/
|
|
16
|
+
export function resolvePreparedSlotValues(
|
|
17
|
+
ps: PreparedStatementInternals,
|
|
18
|
+
userParams: Record<string, unknown>,
|
|
19
|
+
): unknown[] {
|
|
20
|
+
return ps.slots.map((slot) => {
|
|
21
|
+
if (slot.kind === 'literal') return slot.value;
|
|
22
|
+
if (!Object.hasOwn(userParams, slot.name)) {
|
|
23
|
+
throw runtimeError(
|
|
24
|
+
'RUNTIME.PREPARE_MISSING_PARAM',
|
|
25
|
+
`Prepared statement execute is missing parameter '${slot.name}'`,
|
|
26
|
+
{ name: slot.name },
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return userParams[slot.name];
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function encodePreparedParams(
|
|
34
|
+
ps: PreparedStatementInternals,
|
|
35
|
+
userParams: Record<string, unknown>,
|
|
36
|
+
ctx: SqlCodecCallContext,
|
|
37
|
+
contractCodecs?: ContractCodecRegistry,
|
|
38
|
+
): Promise<readonly unknown[]> {
|
|
39
|
+
const resolved = resolvePreparedSlotValues(ps, userParams);
|
|
40
|
+
return encodeParamsWithMetadata(resolved, ps.paramMetadata, ctx, contractCodecs);
|
|
41
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { PlanMeta } from '@prisma-next/contract/types';
|
|
2
|
+
import type {
|
|
3
|
+
AsyncIterableResult,
|
|
4
|
+
RuntimeExecuteOptions,
|
|
5
|
+
} from '@prisma-next/framework-components/runtime';
|
|
6
|
+
import type { AnyQueryAst, LoweredParam } from '@prisma-next/sql-relational-core/ast';
|
|
7
|
+
import type { DecodeContext } from '../codecs/decoding';
|
|
8
|
+
import type { ParamMetadata } from '../codecs/encoding';
|
|
9
|
+
import type { RuntimeQueryable } from '../sql-runtime';
|
|
10
|
+
import type { ParamsFromDeclaration, PreparedStatement } from './types';
|
|
11
|
+
|
|
12
|
+
export interface PreparedStatementInternals {
|
|
13
|
+
readonly sql: string;
|
|
14
|
+
readonly ast: AnyQueryAst;
|
|
15
|
+
readonly meta: PlanMeta;
|
|
16
|
+
readonly slots: readonly LoweredParam[];
|
|
17
|
+
readonly decodeContext: DecodeContext;
|
|
18
|
+
readonly paramMetadata: readonly ParamMetadata[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class PreparedStatementImpl<Params, Row>
|
|
22
|
+
implements PreparedStatement<Params, Row>, PreparedStatementInternals
|
|
23
|
+
{
|
|
24
|
+
readonly sql: string;
|
|
25
|
+
readonly ast: AnyQueryAst;
|
|
26
|
+
readonly meta: PlanMeta;
|
|
27
|
+
readonly slots: readonly LoweredParam[];
|
|
28
|
+
readonly decodeContext: DecodeContext;
|
|
29
|
+
readonly paramMetadata: readonly ParamMetadata[];
|
|
30
|
+
|
|
31
|
+
constructor(internals: PreparedStatementInternals) {
|
|
32
|
+
this.sql = internals.sql;
|
|
33
|
+
this.ast = internals.ast;
|
|
34
|
+
this.meta = internals.meta;
|
|
35
|
+
this.slots = internals.slots;
|
|
36
|
+
this.decodeContext = internals.decodeContext;
|
|
37
|
+
this.paramMetadata = internals.paramMetadata;
|
|
38
|
+
Object.freeze(this);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
execute(
|
|
42
|
+
target: RuntimeQueryable,
|
|
43
|
+
params: Params,
|
|
44
|
+
options?: RuntimeExecuteOptions,
|
|
45
|
+
): AsyncIterableResult<Row> {
|
|
46
|
+
return target.executePrepared(this, params, options);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type { ParamsFromDeclaration };
|