@prisma-next/sql-runtime 0.11.0 → 0.12.0
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/README.md +14 -3
- package/dist/{exports-BsRNNJxU.mjs → exports-CXYd2w6k.mjs} +66 -48
- package/dist/exports-CXYd2w6k.mjs.map +1 -0
- package/dist/{index-B2sP_QGE.d.mts → index-DTr7KoUs.d.mts} +34 -11
- package/dist/index-DTr7KoUs.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/test/utils.d.mts +16 -6
- package/dist/test/utils.d.mts.map +1 -1
- package/dist/test/utils.mjs +22 -7
- package/dist/test/utils.mjs.map +1 -1
- package/package.json +26 -15
- package/src/codecs/decoding.ts +9 -11
- package/src/exports/index.ts +1 -1
- package/src/runtime-spi.ts +19 -5
- package/src/sql-context.ts +56 -9
- package/src/sql-marker.ts +1 -1
- package/src/sql-runtime.ts +52 -64
- package/dist/exports-BsRNNJxU.mjs.map +0 -1
- package/dist/index-B2sP_QGE.d.mts.map +0 -1
|
@@ -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":";;;;;;;;;;;;;;;;;;;iBAuEsB,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;;AAF1E;;iBAUsB,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,2BAA2B;;;;iBAoBd,0BAAA,CAAA,GAA8B,0BAA0B;;AAjLG;AAQ3E;;;iBA4LgB,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;;;AAjOzB;AAOV;;iBAkOgB,iBAAA,CAAA,GAAqB,WAAW;AAAA,iBA0FhC,0BAAA,CAA2B,MAAA,EAAQ,MAAA,SAAe,iBAAA,IAAT,uCAAA,CAA2B,SAAA;EAAA,yCAAA,kCAAA,CAAA,YAAA;EAAA;;iBAIpE,kBAAA,CAAA,GAAkB,8BAAA,CAAA,iBAAA;AAAA,iBAIlB,kBAAA,CACd,QAAA,EAAU,OAAA,CAAQ,IAAA,CAAK,QAAA,CAAS,UAAA;EAC9B,WAAA;EACA,WAAA;EACA,MAAA,GAAS,MAAA,SAAe,iBAAA;EACxB,MAAA,GAAS,QAAA,CAAS,UAAA;EAClB,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,eAAA;AAAA,IAExB,QAAA,CAAS,UAAA;AAAA,iBA2BI,OAAA,CAAA,GAAW,WAAW"}
|
package/dist/test/utils.mjs
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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-CXYd2w6k.mjs";
|
|
2
2
|
import { runtimeError } from "@prisma-next/framework-components/runtime";
|
|
3
3
|
import { SelectAst, TableSource } from "@prisma-next/sql-relational-core/ast";
|
|
4
4
|
import { instantiateExecutionStack } from "@prisma-next/framework-components/execution";
|
|
5
5
|
import { canonicalizeJson } from "@prisma-next/framework-components/utils";
|
|
6
|
-
import { SqlStorage } from "@prisma-next/sql-contract/types";
|
|
6
|
+
import { SqlStorage, SqlUnboundNamespace, buildSqlNamespace } from "@prisma-next/sql-contract/types";
|
|
7
7
|
import { coreHash, profileHash } from "@prisma-next/contract/types";
|
|
8
|
+
import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
|
|
8
9
|
import { builtinGeneratorIds } from "@prisma-next/ids";
|
|
9
10
|
import { generateId } from "@prisma-next/ids/runtime";
|
|
10
|
-
import { collectAsync, collectAsync as collectAsync$1, createDevDatabase, drainAsyncIterable, teardownTestDatabase, withClient } from "@prisma-next/test-utils";
|
|
11
|
+
import { applicationDomainOf, collectAsync, collectAsync as collectAsync$1, createDevDatabase, drainAsyncIterable, teardownTestDatabase, withClient } from "@prisma-next/test-utils";
|
|
11
12
|
//#region test/test-codec.ts
|
|
12
13
|
function defineTestCodec(config) {
|
|
13
14
|
const identity = (v) => v;
|
|
@@ -155,6 +156,7 @@ function createTestAdapterDescriptor(adapter) {
|
|
|
155
156
|
const descriptors = descriptorsFromCodecs(adapter.__codecs);
|
|
156
157
|
return {
|
|
157
158
|
kind: "adapter",
|
|
159
|
+
rawCodecInferer: { inferCodec: () => "pg/text" },
|
|
158
160
|
id: "test-adapter",
|
|
159
161
|
version: "0.0.1",
|
|
160
162
|
familyId: "sql",
|
|
@@ -299,6 +301,15 @@ function createStubAdapter() {
|
|
|
299
301
|
}
|
|
300
302
|
};
|
|
301
303
|
}
|
|
304
|
+
function unboundNamespaceWithTables(tables) {
|
|
305
|
+
return buildSqlNamespace({
|
|
306
|
+
id: UNBOUND_NAMESPACE_ID,
|
|
307
|
+
tables
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
function emptySqlTestDomain() {
|
|
311
|
+
return applicationDomainOf({ models: {} });
|
|
312
|
+
}
|
|
302
313
|
function createTestContract(contract) {
|
|
303
314
|
const { execution, ...rest } = contract;
|
|
304
315
|
const storageHashValue = coreHash(rest["storageHash"] ?? "sha256:testcore");
|
|
@@ -307,9 +318,13 @@ function createTestContract(contract) {
|
|
|
307
318
|
targetFamily: rest["targetFamily"] ?? "sql",
|
|
308
319
|
storage: rest["storage"] ? new SqlStorage({
|
|
309
320
|
...rest["storage"],
|
|
310
|
-
storageHash: storageHashValue
|
|
311
|
-
|
|
312
|
-
|
|
321
|
+
storageHash: storageHashValue,
|
|
322
|
+
namespaces: rest["storage"].namespaces ?? { __unbound__: SqlUnboundNamespace.instance }
|
|
323
|
+
}) : new SqlStorage({
|
|
324
|
+
storageHash: storageHashValue,
|
|
325
|
+
namespaces: { __unbound__: SqlUnboundNamespace.instance }
|
|
326
|
+
}),
|
|
327
|
+
domain: rest["domain"] ?? applicationDomainOf({ models: rest["models"] ?? {} }),
|
|
313
328
|
roots: rest["roots"] ?? {},
|
|
314
329
|
capabilities: rest["capabilities"] ?? {},
|
|
315
330
|
extensionPacks: rest["extensionPacks"] ?? {},
|
|
@@ -322,6 +337,6 @@ function stubAst() {
|
|
|
322
337
|
return SelectAst.from(TableSource.named("stub"));
|
|
323
338
|
}
|
|
324
339
|
//#endregion
|
|
325
|
-
export { buildTestContractCodecs, collectAsync, createDevDatabase, createStubAdapter, createTestAdapterDescriptor, createTestContext, createTestContract, createTestStackInstance, createTestTargetDescriptor, descriptorsFromCodecs, drainPlanExecution, executePlanAndCollect, executeStatement, setupTestDatabase, stubAst, teardownTestDatabase, withClient, writeTestContractMarker };
|
|
340
|
+
export { buildTestContractCodecs, collectAsync, createDevDatabase, createStubAdapter, createTestAdapterDescriptor, createTestContext, createTestContract, createTestStackInstance, createTestTargetDescriptor, descriptorsFromCodecs, drainPlanExecution, emptySqlTestDomain, executePlanAndCollect, executeStatement, setupTestDatabase, stubAst, teardownTestDatabase, unboundNamespaceWithTables, withClient, writeTestContractMarker };
|
|
326
341
|
|
|
327
342
|
//# sourceMappingURL=utils.mjs.map
|
package/dist/test/utils.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 }),\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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"}
|
|
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 {\n type Contract,\n type ContractModelBase,\n coreHash,\n profileHash,\n} 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 { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\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 {\n buildSqlNamespace,\n SqlStorage,\n type SqlStorageInput,\n SqlUnboundNamespace,\n type StorageTableInput,\n} 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 { applicationDomainOf, 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 rawCodecInferer: { inferCodec: () => 'pg/text' },\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 unboundNamespaceWithTables(tables: Record<string, StorageTableInput>) {\n return buildSqlNamespace({ id: UNBOUND_NAMESPACE_ID, tables });\n}\n\nexport function emptySqlTestDomain() {\n return applicationDomainOf({ models: {} });\n}\n\nexport function createTestContract(\n contract: Partial<Omit<Contract<SqlStorage>, 'profileHash' | 'storage' | 'domain'>> & {\n storageHash?: string;\n profileHash?: string;\n models?: Record<string, ContractModelBase>;\n domain?: Contract<SqlStorage>['domain'];\n storage?: Partial<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({\n ...rest['storage'],\n storageHash: storageHashValue,\n namespaces: rest['storage'].namespaces ?? { __unbound__: SqlUnboundNamespace.instance },\n })\n : new SqlStorage({\n storageHash: storageHashValue,\n namespaces: { __unbound__: SqlUnboundNamespace.instance },\n }),\n domain: rest['domain'] ?? applicationDomainOf({ 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,43 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
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.
|
|
10
|
-
"@prisma-next/utils": "0.
|
|
11
|
-
"@prisma-next/framework-components": "0.
|
|
12
|
-
"@prisma-next/ids": "0.
|
|
13
|
-
"@prisma-next/operations": "0.
|
|
14
|
-
"@prisma-next/sql-contract": "0.
|
|
15
|
-
"@prisma-next/sql-operations": "0.
|
|
16
|
-
"@prisma-next/sql-relational-core": "0.
|
|
9
|
+
"@prisma-next/contract": "0.12.0",
|
|
10
|
+
"@prisma-next/utils": "0.12.0",
|
|
11
|
+
"@prisma-next/framework-components": "0.12.0",
|
|
12
|
+
"@prisma-next/ids": "0.12.0",
|
|
13
|
+
"@prisma-next/operations": "0.12.0",
|
|
14
|
+
"@prisma-next/sql-contract": "0.12.0",
|
|
15
|
+
"@prisma-next/sql-operations": "0.12.0",
|
|
16
|
+
"@prisma-next/sql-relational-core": "0.12.0",
|
|
17
17
|
"arktype": "^2.2.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@prisma-next/test-utils": "0.
|
|
21
|
-
"@prisma-next/tsconfig": "0.
|
|
20
|
+
"@prisma-next/test-utils": "0.12.0",
|
|
21
|
+
"@prisma-next/tsconfig": "0.12.0",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.20.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.
|
|
24
|
+
"@prisma-next/tsdown": "0.12.0",
|
|
25
25
|
"tsdown": "0.22.0",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.6"
|
|
28
28
|
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"typescript": ">=5.9"
|
|
31
|
+
},
|
|
32
|
+
"peerDependenciesMeta": {
|
|
33
|
+
"typescript": {
|
|
34
|
+
"optional": true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
29
37
|
"files": [
|
|
30
38
|
"dist",
|
|
31
39
|
"src"
|
|
32
40
|
],
|
|
41
|
+
"main": "./dist/index.mjs",
|
|
42
|
+
"module": "./dist/index.mjs",
|
|
43
|
+
"types": "./dist/index.d.mts",
|
|
33
44
|
"exports": {
|
|
34
45
|
".": "./dist/index.mjs",
|
|
35
46
|
"./test/utils": "./dist/test/utils.mjs",
|
|
36
47
|
"./package.json": "./package.json"
|
|
37
48
|
},
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=24"
|
|
51
|
+
},
|
|
41
52
|
"repository": {
|
|
42
53
|
"type": "git",
|
|
43
54
|
"url": "https://github.com/prisma/prisma-next.git",
|
package/src/codecs/decoding.ts
CHANGED
|
@@ -135,20 +135,18 @@ function decodeIncludeAggregate(alias: string, wireValue: unknown): unknown {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
try {
|
|
138
|
-
let parsed: unknown;
|
|
139
138
|
if (typeof wireValue === 'string') {
|
|
140
|
-
|
|
141
|
-
} else if (Array.isArray(wireValue)) {
|
|
142
|
-
parsed = wireValue;
|
|
143
|
-
} else {
|
|
144
|
-
parsed = JSON.parse(String(wireValue));
|
|
139
|
+
return JSON.parse(wireValue);
|
|
145
140
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
141
|
+
if (typeof wireValue === 'object') {
|
|
142
|
+
// Driver layer has already parsed the JSON wire value (pg returns
|
|
143
|
+
// json / jsonb columns as JS values). Pass through unchanged —
|
|
144
|
+
// both row include arrays (`json_agg`) and scalar / combine
|
|
145
|
+
// include envelopes (`json_build_object`) flow through this path,
|
|
146
|
+
// each with their own downstream shape decoder.
|
|
147
|
+
return wireValue;
|
|
149
148
|
}
|
|
150
|
-
|
|
151
|
-
return parsed;
|
|
149
|
+
return JSON.parse(String(wireValue));
|
|
152
150
|
} catch (error) {
|
|
153
151
|
wrapIncludeAggregateFailure(error, alias, wireValue);
|
|
154
152
|
}
|
package/src/exports/index.ts
CHANGED
package/src/runtime-spi.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ExecutionPlan } from '@prisma-next/framework-components/runtime';
|
|
|
2
2
|
import type { MarkerReadResult, SqlQueryable } from '@prisma-next/sql-relational-core/ast';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Reader of the SQL contract marker. SQL runtimes call `readMarker` before executing user queries (
|
|
5
|
+
* Reader of the SQL contract marker. SQL runtimes call `readMarker` before executing user queries (unless `verifyMarker` is false). The adapter owns the full marker-read flow — probing for storage, issuing the read, decoding the row — and returns a tagged result so callers can distinguish "marker storage missing", "no row for this space", and "present".
|
|
6
6
|
*/
|
|
7
7
|
export interface MarkerReader {
|
|
8
8
|
readMarker(queryable: SqlQueryable): Promise<MarkerReadResult>;
|
|
@@ -22,10 +22,24 @@ export interface RuntimeFamilyAdapter<TContract = unknown> {
|
|
|
22
22
|
validatePlan(plan: ExecutionPlan, contract: TContract): void;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Controls whether the runtime reads and checks the contract marker row on first execute.
|
|
27
|
+
*
|
|
28
|
+
* - `'onFirstUse'` (default when omitted): the marker is read once per runtime lifetime, on the
|
|
29
|
+
* first `execute()` call. Any hash mismatch or absent marker emits a structured `warn`-level log
|
|
30
|
+
* through the runtime's {@link RuntimeLog} and the query proceeds. Subsequent queries skip the
|
|
31
|
+
* marker reader entirely.
|
|
32
|
+
* - `false`: the marker reader is never invoked. No log line is emitted. Use this to opt out of
|
|
33
|
+
* the diagnostic entirely (e.g. during a known deploy-skew window).
|
|
34
|
+
*
|
|
35
|
+
* The string-or-false shape is forward-compatible: future modes such as `'startup'` (eager check
|
|
36
|
+
* inside the wrapper `connect()` step) can be added as additive union members without an API break.
|
|
37
|
+
* `true` is intentionally not permitted — modes are always named.
|
|
38
|
+
*
|
|
39
|
+
* Default-on so contract drift surfaces by default — teams who never thought to enable the diagnostic
|
|
40
|
+
* still see the warning when something goes wrong.
|
|
41
|
+
*/
|
|
42
|
+
export type VerifyMarkerOption = 'onFirstUse' | false;
|
|
29
43
|
|
|
30
44
|
export type TelemetryOutcome = 'success' | 'runtime-error';
|
|
31
45
|
|
package/src/sql-context.ts
CHANGED
|
@@ -9,7 +9,10 @@ import type {
|
|
|
9
9
|
CodecRef,
|
|
10
10
|
} from '@prisma-next/framework-components/codec';
|
|
11
11
|
import type { ComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
checkContractComponentRequirements,
|
|
14
|
+
mergeCapabilityMatrices,
|
|
15
|
+
} from '@prisma-next/framework-components/components';
|
|
13
16
|
import {
|
|
14
17
|
createExecutionStack,
|
|
15
18
|
type ExecutionStack,
|
|
@@ -30,6 +33,7 @@ import {
|
|
|
30
33
|
type StorageTable,
|
|
31
34
|
type StorageTypeInstance,
|
|
32
35
|
} from '@prisma-next/sql-contract/types';
|
|
36
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
33
37
|
|
|
34
38
|
// Framework `Namespace.tables` is widened to `Record<string, object>` so
|
|
35
39
|
// emitted `contract.d.ts` table literals satisfy it structurally. At
|
|
@@ -39,6 +43,15 @@ import {
|
|
|
39
43
|
// weakening the substrate type.
|
|
40
44
|
type SqlNamespaceTables = Readonly<Record<string, StorageTable>>;
|
|
41
45
|
|
|
46
|
+
function documentScopedCodecTypes(
|
|
47
|
+
contract: Contract<SqlStorage>,
|
|
48
|
+
): Record<string, StorageTypeInstance> | undefined {
|
|
49
|
+
return blindCast<
|
|
50
|
+
Record<string, StorageTypeInstance> | undefined,
|
|
51
|
+
'SqlStorage.types is typed for generic access; runtime shape is guaranteed by contract schema validation'
|
|
52
|
+
>(contract.storage.types);
|
|
53
|
+
}
|
|
54
|
+
|
|
42
55
|
import {
|
|
43
56
|
createSqlOperationRegistry,
|
|
44
57
|
type SqlOperationDescriptors,
|
|
@@ -52,6 +65,7 @@ import type {
|
|
|
52
65
|
SqlDriver,
|
|
53
66
|
} from '@prisma-next/sql-relational-core/ast';
|
|
54
67
|
import { buildCodecDescriptorRegistry } from '@prisma-next/sql-relational-core/codec-descriptor-registry';
|
|
68
|
+
import type { RawCodecInferer } from '@prisma-next/sql-relational-core/expression';
|
|
55
69
|
import type {
|
|
56
70
|
AppliedMutationDefault,
|
|
57
71
|
CodecDescriptorRegistry,
|
|
@@ -113,7 +127,12 @@ export interface SqlRuntimeAdapterDescriptor<
|
|
|
113
127
|
TTargetId
|
|
114
128
|
> = SqlRuntimeAdapterInstance<TTargetId>,
|
|
115
129
|
> extends RuntimeAdapterDescriptor<'sql', TTargetId, TAdapterInstance>,
|
|
116
|
-
SqlStaticContributions {
|
|
130
|
+
SqlStaticContributions {
|
|
131
|
+
/**
|
|
132
|
+
* Codec inferer used by `fns.raw` to look up the codec id for a bare-literal interpolation. Required on every SQL adapter descriptor — the facade reads it off the descriptor at client-construction time without instantiating the runtime adapter.
|
|
133
|
+
*/
|
|
134
|
+
readonly rawCodecInferer: RawCodecInferer;
|
|
135
|
+
}
|
|
117
136
|
|
|
118
137
|
export interface SqlRuntimeExtensionDescriptor<TTargetId extends string = string>
|
|
119
138
|
extends RuntimeExtensionDescriptor<'sql', TTargetId, SqlRuntimeExtensionInstance<TTargetId>>,
|
|
@@ -343,18 +362,18 @@ function collectTypeRefSites(
|
|
|
343
362
|
|
|
344
363
|
function initializeTypeHelpers(
|
|
345
364
|
storage: SqlStorage,
|
|
365
|
+
documentTypes: Record<string, StorageTypeInstance> | undefined,
|
|
346
366
|
codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
|
|
347
367
|
): TypeHelperRegistry {
|
|
348
368
|
const helpers: TypeHelperRegistry = {};
|
|
349
|
-
const storageTypes = storage.types;
|
|
350
369
|
|
|
351
|
-
if (!
|
|
370
|
+
if (!documentTypes) {
|
|
352
371
|
return helpers;
|
|
353
372
|
}
|
|
354
373
|
|
|
355
374
|
const typeRefSites = collectTypeRefSites(storage);
|
|
356
375
|
|
|
357
|
-
for (const [typeName, typeInstance] of Object.entries(
|
|
376
|
+
for (const [typeName, typeInstance] of Object.entries(documentTypes)) {
|
|
358
377
|
const enumView = readEnumViewIfApplicable(typeInstance);
|
|
359
378
|
const codecId = enumView ? enumView.codecId : (typeInstance as StorageTypeInstance).codecId;
|
|
360
379
|
const typeParams = enumView
|
|
@@ -505,7 +524,7 @@ function buildContractCodecRegistry(
|
|
|
505
524
|
const nameByKey = new Map<string, string>();
|
|
506
525
|
|
|
507
526
|
const typeRefSites = collectTypeRefSites(contract.storage);
|
|
508
|
-
for (const [typeName, typeInstance] of Object.entries(contract
|
|
527
|
+
for (const [typeName, typeInstance] of Object.entries(documentScopedCodecTypes(contract) ?? {})) {
|
|
509
528
|
const enumView = readEnumViewIfApplicable(typeInstance);
|
|
510
529
|
const ref: CodecRef = enumView
|
|
511
530
|
? {
|
|
@@ -758,10 +777,34 @@ export function createExecutionContext<
|
|
|
758
777
|
>(options: {
|
|
759
778
|
readonly contract: TContract;
|
|
760
779
|
readonly stack: SqlExecutionStack<TTargetId>;
|
|
780
|
+
/**
|
|
781
|
+
* Optional driver descriptor. When provided, its `capabilities` are folded into the contract's capability matrix alongside the target, adapter, and extension packs — matching the merge `enrichContract` performs at CLI emit time. The driver is *only* consulted as a capability source here; runtime driver lifecycle is wired separately via {@link instantiateExecutionStack} + `runtime.connect`.
|
|
782
|
+
*/
|
|
783
|
+
readonly driver?: RuntimeDriverDescriptor<
|
|
784
|
+
'sql',
|
|
785
|
+
TTargetId,
|
|
786
|
+
unknown,
|
|
787
|
+
SqlRuntimeDriverInstance<TTargetId>
|
|
788
|
+
>;
|
|
761
789
|
}): ExecutionContext<TContract> {
|
|
762
|
-
const {
|
|
790
|
+
const { stack, driver } = options;
|
|
791
|
+
|
|
792
|
+
assertExecutionStackContractRequirements(options.contract, stack);
|
|
763
793
|
|
|
764
|
-
|
|
794
|
+
const capabilityContributors: ReadonlyArray<{ readonly capabilities?: unknown }> = [
|
|
795
|
+
stack.target,
|
|
796
|
+
stack.adapter,
|
|
797
|
+
...(driver ? [driver] : []),
|
|
798
|
+
...stack.extensionPacks,
|
|
799
|
+
];
|
|
800
|
+
const mergedCapabilities = mergeCapabilityMatrices(
|
|
801
|
+
options.contract.capabilities,
|
|
802
|
+
capabilityContributors,
|
|
803
|
+
);
|
|
804
|
+
const contract: TContract = {
|
|
805
|
+
...options.contract,
|
|
806
|
+
capabilities: mergedCapabilities,
|
|
807
|
+
};
|
|
765
808
|
|
|
766
809
|
const contributors: Array<SqlStaticContributions & ComponentDescriptor<string>> = [
|
|
767
810
|
stack.target,
|
|
@@ -789,7 +832,11 @@ export function createExecutionContext<
|
|
|
789
832
|
validateColumnTypeParams(contract.storage, parameterizedCodecDescriptors);
|
|
790
833
|
}
|
|
791
834
|
|
|
792
|
-
const types = initializeTypeHelpers(
|
|
835
|
+
const types = initializeTypeHelpers(
|
|
836
|
+
contract.storage,
|
|
837
|
+
documentScopedCodecTypes(contract),
|
|
838
|
+
parameterizedCodecDescriptors,
|
|
839
|
+
);
|
|
793
840
|
|
|
794
841
|
const contractCodecs = buildContractCodecRegistry(contract, codecDescriptors);
|
|
795
842
|
|
package/src/sql-marker.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface WriteMarkerInput {
|
|
|
13
13
|
* Logical space identifier for this marker row. Required at every
|
|
14
14
|
* call site so the type system surfaces every place that needs to
|
|
15
15
|
* thread the value (rather than letting an `?? APP_SPACE_ID`
|
|
16
|
-
* fall-through silently collapse
|
|
16
|
+
* fall-through silently collapse per-space markers onto the
|
|
17
17
|
* `'app'` row). App-plan callers pass {@link APP_SPACE_ID}
|
|
18
18
|
* (`'app'`); per-extension callers pass the extension's space id.
|
|
19
19
|
*/
|