@prisma-next/adapter-sqlite 0.13.0 → 0.14.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.
@@ -1 +1 @@
1
- {"version":3,"file":"control.mjs","names":[],"sources":["../src/core/control-mutation-defaults.ts","../src/exports/control.ts"],"sourcesContent":["import type { ExecutionMutationDefaultValue } from '@prisma-next/contract/types';\nimport { timestampNowControlDescriptor } from '@prisma-next/family-sql/control';\nimport type {\n ControlMutationDefaultEntry,\n MutationDefaultGeneratorDescriptor,\n} from '@prisma-next/framework-components/control';\nimport {\n builtinGeneratorRegistryMetadata,\n resolveBuiltinGeneratedColumnDescriptor,\n} from '@prisma-next/ids';\nimport type {\n DefaultFunctionLoweringContext,\n DefaultFunctionLoweringHandler,\n} from '@prisma-next/sql-contract-psl';\nimport {\n SQLITE_BIGINT_CODEC_ID,\n SQLITE_BLOB_CODEC_ID,\n SQLITE_DATETIME_CODEC_ID,\n SQLITE_INTEGER_CODEC_ID,\n SQLITE_JSON_CODEC_ID,\n SQLITE_REAL_CODEC_ID,\n SQLITE_TEXT_CODEC_ID,\n} from '@prisma-next/target-sqlite/codec-ids';\n\ntype LoweredDefaultResult = ReturnType<DefaultFunctionLoweringHandler>;\ntype ParsedDefaultFunctionCall = Parameters<DefaultFunctionLoweringHandler>[0]['call'];\n\nfunction invalidArgumentDiagnostic(input: {\n readonly context: DefaultFunctionLoweringContext;\n readonly span: ParsedDefaultFunctionCall['span'];\n readonly message: string;\n}): LoweredDefaultResult {\n return {\n ok: false,\n diagnostic: {\n code: 'PSL_INVALID_DEFAULT_FUNCTION_ARGUMENT',\n message: input.message,\n sourceId: input.context.sourceId,\n span: input.span,\n },\n };\n}\n\nfunction executionGenerator(\n id: ExecutionMutationDefaultValue['id'],\n params?: Record<string, unknown>,\n): LoweredDefaultResult {\n return {\n ok: true,\n value: {\n kind: 'execution',\n generated: {\n kind: 'generator',\n id,\n ...(params ? { params } : {}),\n },\n },\n };\n}\n\nfunction expectNoArgs(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n readonly usage: string;\n}): LoweredDefaultResult | undefined {\n if (input.call.args.length === 0) {\n return undefined;\n }\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message: `Default function \"${input.call.name}\" does not accept arguments. Use ${input.usage}.`,\n });\n}\n\nfunction parseIntegerArgument(raw: string): number | undefined {\n const trimmed = raw.trim();\n if (!/^-?\\d+$/.test(trimmed)) {\n return undefined;\n }\n const value = Number(trimmed);\n if (!Number.isInteger(value)) {\n return undefined;\n }\n return value;\n}\n\nfunction parseStringLiteral(raw: string): string | undefined {\n const match = raw.trim().match(/^(['\"])(.*)\\1$/s);\n if (!match) {\n return undefined;\n }\n return match[2] ?? '';\n}\n\nfunction lowerAutoincrement(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n const maybeNoArgs = expectNoArgs({\n call: input.call,\n context: input.context,\n usage: '`autoincrement()`',\n });\n if (maybeNoArgs) {\n return maybeNoArgs;\n }\n return {\n ok: true,\n value: {\n kind: 'storage',\n defaultValue: {\n kind: 'function',\n expression: 'autoincrement()',\n },\n },\n };\n}\n\nfunction lowerNow(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n const maybeNoArgs = expectNoArgs({\n call: input.call,\n context: input.context,\n usage: '`now()`',\n });\n if (maybeNoArgs) {\n return maybeNoArgs;\n }\n return {\n ok: true,\n value: {\n kind: 'storage',\n defaultValue: {\n kind: 'function',\n expression: 'now()',\n },\n },\n };\n}\n\nfunction lowerUuid(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n if (input.call.args.length === 0) {\n return executionGenerator('uuidv4');\n }\n if (input.call.args.length !== 1) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message:\n 'Default function \"uuid\" accepts at most one version argument: `uuid()`, `uuid(4)`, or `uuid(7)`.',\n });\n }\n const version = parseIntegerArgument(input.call.args[0]?.raw ?? '');\n if (version === 4) {\n return executionGenerator('uuidv4');\n }\n if (version === 7) {\n return executionGenerator('uuidv7');\n }\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message:\n 'Default function \"uuid\" supports only `uuid()`, `uuid(4)`, or `uuid(7)` in SQL PSL provider v1.',\n });\n}\n\nfunction lowerCuid(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n if (input.call.args.length === 0) {\n return {\n ok: false,\n diagnostic: {\n code: 'PSL_UNKNOWN_DEFAULT_FUNCTION',\n message:\n 'Default function \"cuid()\" is not supported in SQL PSL provider v1. Use `cuid(2)` instead.',\n sourceId: input.context.sourceId,\n span: input.call.span,\n },\n };\n }\n if (input.call.args.length !== 1) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message: 'Default function \"cuid\" accepts exactly one version argument: `cuid(2)`.',\n });\n }\n const version = parseIntegerArgument(input.call.args[0]?.raw ?? '');\n if (version === 2) {\n return executionGenerator('cuid2');\n }\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message: 'Default function \"cuid\" supports only `cuid(2)` in SQL PSL provider v1.',\n });\n}\n\nfunction lowerUlid(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n const maybeNoArgs = expectNoArgs({\n call: input.call,\n context: input.context,\n usage: '`ulid()`',\n });\n if (maybeNoArgs) {\n return maybeNoArgs;\n }\n return executionGenerator('ulid');\n}\n\nfunction lowerNanoid(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n if (input.call.args.length === 0) {\n return executionGenerator('nanoid');\n }\n if (input.call.args.length !== 1) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message:\n 'Default function \"nanoid\" accepts at most one size argument: `nanoid()` or `nanoid(<2-255>)`.',\n });\n }\n const size = parseIntegerArgument(input.call.args[0]?.raw ?? '');\n if (size !== undefined && size >= 2 && size <= 255) {\n return executionGenerator('nanoid', { size });\n }\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message: 'Default function \"nanoid\" size argument must be an integer between 2 and 255.',\n });\n}\n\n/**\n * SQLite spellings that all denote the same wall-clock-now value. Anything\n * matching this set when passed through `dbgenerated(\"...\")` is rewritten\n * to the canonical `now()` form before entering the contract — symmetric\n * with `parseSqliteDefault` on the introspection side, so the verifier\n * compares canonical-vs-canonical and a contract using\n * `dbgenerated(\"CURRENT_TIMESTAMP\")` doesn't drift against the schema it\n * just produced.\n */\nconst NOW_SYNONYMS = new Set(['current_timestamp', \"datetime('now')\", 'datetime(\"now\")', 'now()']);\n\nfunction lowerDbgenerated(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n if (input.call.args.length !== 1) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message:\n 'Default function \"dbgenerated\" requires exactly one string argument: `dbgenerated(\"...\")`.',\n });\n }\n const rawExpression = parseStringLiteral(input.call.args[0]?.raw ?? '');\n if (rawExpression === undefined) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message: 'Default function \"dbgenerated\" argument must be a string literal.',\n });\n }\n const trimmed = rawExpression.trim();\n if (trimmed.length === 0) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message: 'Default function \"dbgenerated\" argument cannot be empty.',\n });\n }\n const expression = NOW_SYNONYMS.has(trimmed.toLowerCase()) ? 'now()' : trimmed;\n return {\n ok: true,\n value: {\n kind: 'storage',\n defaultValue: {\n kind: 'function',\n expression,\n },\n },\n };\n}\n\nconst sqliteDefaultFunctionRegistryEntries = [\n ['autoincrement', { lower: lowerAutoincrement, usageSignatures: ['autoincrement()'] }],\n ['now', { lower: lowerNow, usageSignatures: ['now()'] }],\n ['uuid', { lower: lowerUuid, usageSignatures: ['uuid()', 'uuid(4)', 'uuid(7)'] }],\n ['cuid', { lower: lowerCuid, usageSignatures: ['cuid(2)'] }],\n ['ulid', { lower: lowerUlid, usageSignatures: ['ulid()'] }],\n ['nanoid', { lower: lowerNanoid, usageSignatures: ['nanoid()', 'nanoid(<2-255>)'] }],\n ['dbgenerated', { lower: lowerDbgenerated, usageSignatures: ['dbgenerated(\"...\")'] }],\n] satisfies ReadonlyArray<readonly [string, ControlMutationDefaultEntry]>;\n\nconst sqliteScalarTypeDescriptors = new Map<string, string>([\n ['String', SQLITE_TEXT_CODEC_ID],\n ['Int', SQLITE_INTEGER_CODEC_ID],\n ['BigInt', SQLITE_BIGINT_CODEC_ID],\n ['Float', SQLITE_REAL_CODEC_ID],\n ['Decimal', SQLITE_TEXT_CODEC_ID],\n ['DateTime', SQLITE_DATETIME_CODEC_ID],\n ['Json', SQLITE_JSON_CODEC_ID],\n ['Bytes', SQLITE_BLOB_CODEC_ID],\n]);\n\nexport function createSqliteDefaultFunctionRegistry(): ReadonlyMap<\n string,\n ControlMutationDefaultEntry\n> {\n return new Map(sqliteDefaultFunctionRegistryEntries);\n}\n\nexport function createSqliteMutationDefaultGeneratorDescriptors(): readonly MutationDefaultGeneratorDescriptor[] {\n return [\n ...builtinGeneratorRegistryMetadata.map(\n ({ id, applicableCodecIds }): MutationDefaultGeneratorDescriptor => ({\n id,\n applicableCodecIds,\n resolveGeneratedColumnDescriptor: ({ generated }) => {\n if (generated.kind !== 'generator' || generated.id !== id) {\n return undefined;\n }\n const descriptor = resolveBuiltinGeneratedColumnDescriptor({\n id,\n ...(generated.params ? { params: generated.params } : {}),\n });\n return {\n codecId: descriptor.type.codecId,\n nativeType: descriptor.type.nativeType,\n ...(descriptor.type.typeRef ? { typeRef: descriptor.type.typeRef } : {}),\n ...(descriptor.typeParams ? { typeParams: descriptor.typeParams } : {}),\n };\n },\n }),\n ),\n timestampNowControlDescriptor(),\n ];\n}\n\nexport function createSqliteScalarTypeDescriptors(): ReadonlyMap<string, string> {\n return new Map(sqliteScalarTypeDescriptors);\n}\n","import type { SqlControlAdapterDescriptor } from '@prisma-next/family-sql/control';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport { SqliteControlAdapter } from '../core/control-adapter';\nimport {\n createSqliteDefaultFunctionRegistry,\n createSqliteMutationDefaultGeneratorDescriptors,\n createSqliteScalarTypeDescriptors,\n} from '../core/control-mutation-defaults';\nimport { sqliteAdapterDescriptorMeta } from '../core/descriptor-meta';\n\nconst sqliteAdapterDescriptor: SqlControlAdapterDescriptor<'sqlite'> = {\n ...sqliteAdapterDescriptorMeta,\n scalarTypeDescriptors: createSqliteScalarTypeDescriptors(),\n controlMutationDefaults: {\n defaultFunctionRegistry: createSqliteDefaultFunctionRegistry(),\n generatorDescriptors: createSqliteMutationDefaultGeneratorDescriptors(),\n },\n create(): SqlControlAdapter<'sqlite'> {\n return new SqliteControlAdapter();\n },\n};\n\nexport default sqliteAdapterDescriptor;\n\n// `parseSqliteDefault`, `normalizeSqliteNativeType`, `quoteIdentifier`,\n// `escapeLiteral`, and `SqlEscapeError` live target-side (one-way\n// `adapter → target` edge, matching Postgres). Re-exported from the\n// adapter so consumers — both internal and downstream — see the same\n// adapter-shaped surface across SQL targets.\nexport { parseSqliteDefault } from '@prisma-next/target-sqlite/default-normalizer';\nexport { normalizeSqliteNativeType } from '@prisma-next/target-sqlite/native-type-normalizer';\nexport {\n escapeLiteral,\n quoteIdentifier,\n SqlEscapeError,\n} from '@prisma-next/target-sqlite/sql-utils';\n\n// `SqlControlAdapterDescriptor` is declared in two places in the codebase\n// (`family-sql/control-adapter` and `family-sql/migrations/types`); the\n// migrations-side declaration narrows `create()`'s return type to the base\n// `ControlAdapterInstance`, hiding `introspect`/`readMarker`. Until that's\n// reconciled upstream, downstream consumers (e2e harness, integration\n// tests) need direct access to the concrete class. Mirrors how Postgres'\n// own package tests import `PostgresControlAdapter` directly.\nexport { SqliteControlAdapter } from '../core/control-adapter';\n"],"mappings":"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"}
1
+ {"version":3,"file":"control.mjs","names":[],"sources":["../src/core/control-mutation-defaults.ts","../src/exports/control.ts"],"sourcesContent":["import type { ExecutionMutationDefaultValue } from '@prisma-next/contract/types';\nimport { timestampNowControlDescriptor } from '@prisma-next/family-sql/control';\nimport type {\n ControlMutationDefaultEntry,\n MutationDefaultGeneratorDescriptor,\n} from '@prisma-next/framework-components/control';\nimport {\n builtinGeneratorRegistryMetadata,\n resolveBuiltinGeneratedColumnDescriptor,\n} from '@prisma-next/ids';\nimport type {\n DefaultFunctionLoweringContext,\n DefaultFunctionLoweringHandler,\n} from '@prisma-next/sql-contract-psl';\nimport {\n SQLITE_BIGINT_CODEC_ID,\n SQLITE_BLOB_CODEC_ID,\n SQLITE_DATETIME_CODEC_ID,\n SQLITE_INTEGER_CODEC_ID,\n SQLITE_JSON_CODEC_ID,\n SQLITE_REAL_CODEC_ID,\n SQLITE_TEXT_CODEC_ID,\n} from '@prisma-next/target-sqlite/codec-ids';\n\ntype LoweredDefaultResult = ReturnType<DefaultFunctionLoweringHandler>;\ntype ParsedDefaultFunctionCall = Parameters<DefaultFunctionLoweringHandler>[0]['call'];\n\nfunction invalidArgumentDiagnostic(input: {\n readonly context: DefaultFunctionLoweringContext;\n readonly span: ParsedDefaultFunctionCall['span'];\n readonly message: string;\n}): LoweredDefaultResult {\n return {\n ok: false,\n diagnostic: {\n code: 'PSL_INVALID_DEFAULT_FUNCTION_ARGUMENT',\n message: input.message,\n sourceId: input.context.sourceId,\n span: input.span,\n },\n };\n}\n\nfunction executionGenerator(\n id: ExecutionMutationDefaultValue['id'],\n params?: Record<string, unknown>,\n): LoweredDefaultResult {\n return {\n ok: true,\n value: {\n kind: 'execution',\n generated: {\n kind: 'generator',\n id,\n ...(params ? { params } : {}),\n },\n },\n };\n}\n\nfunction expectNoArgs(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n readonly usage: string;\n}): LoweredDefaultResult | undefined {\n if (input.call.args.length === 0) {\n return undefined;\n }\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message: `Default function \"${input.call.name}\" does not accept arguments. Use ${input.usage}.`,\n });\n}\n\nfunction parseIntegerArgument(raw: string): number | undefined {\n const trimmed = raw.trim();\n if (!/^-?\\d+$/.test(trimmed)) {\n return undefined;\n }\n const value = Number(trimmed);\n if (!Number.isInteger(value)) {\n return undefined;\n }\n return value;\n}\n\nfunction parseStringLiteral(raw: string): string | undefined {\n const match = raw.trim().match(/^(['\"])(.*)\\1$/s);\n if (!match) {\n return undefined;\n }\n return match[2] ?? '';\n}\n\nfunction lowerAutoincrement(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n const maybeNoArgs = expectNoArgs({\n call: input.call,\n context: input.context,\n usage: '`autoincrement()`',\n });\n if (maybeNoArgs) {\n return maybeNoArgs;\n }\n return {\n ok: true,\n value: {\n kind: 'storage',\n defaultValue: {\n kind: 'function',\n expression: 'autoincrement()',\n },\n },\n };\n}\n\nfunction lowerNow(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n const maybeNoArgs = expectNoArgs({\n call: input.call,\n context: input.context,\n usage: '`now()`',\n });\n if (maybeNoArgs) {\n return maybeNoArgs;\n }\n return {\n ok: true,\n value: {\n kind: 'storage',\n defaultValue: {\n kind: 'function',\n expression: 'now()',\n },\n },\n };\n}\n\nfunction lowerUuid(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n if (input.call.args.length === 0) {\n return executionGenerator('uuidv4');\n }\n if (input.call.args.length !== 1) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message:\n 'Default function \"uuid\" accepts at most one version argument: `uuid()`, `uuid(4)`, or `uuid(7)`.',\n });\n }\n const version = parseIntegerArgument(input.call.args[0]?.raw ?? '');\n if (version === 4) {\n return executionGenerator('uuidv4');\n }\n if (version === 7) {\n return executionGenerator('uuidv7');\n }\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message:\n 'Default function \"uuid\" supports only `uuid()`, `uuid(4)`, or `uuid(7)` in SQL PSL provider v1.',\n });\n}\n\nfunction lowerCuid(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n if (input.call.args.length === 0) {\n return {\n ok: false,\n diagnostic: {\n code: 'PSL_UNKNOWN_DEFAULT_FUNCTION',\n message:\n 'Default function \"cuid()\" is not supported in SQL PSL provider v1. Use `cuid(2)` instead.',\n sourceId: input.context.sourceId,\n span: input.call.span,\n },\n };\n }\n if (input.call.args.length !== 1) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message: 'Default function \"cuid\" accepts exactly one version argument: `cuid(2)`.',\n });\n }\n const version = parseIntegerArgument(input.call.args[0]?.raw ?? '');\n if (version === 2) {\n return executionGenerator('cuid2');\n }\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message: 'Default function \"cuid\" supports only `cuid(2)` in SQL PSL provider v1.',\n });\n}\n\nfunction lowerUlid(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n const maybeNoArgs = expectNoArgs({\n call: input.call,\n context: input.context,\n usage: '`ulid()`',\n });\n if (maybeNoArgs) {\n return maybeNoArgs;\n }\n return executionGenerator('ulid');\n}\n\nfunction lowerNanoid(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n if (input.call.args.length === 0) {\n return executionGenerator('nanoid');\n }\n if (input.call.args.length !== 1) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message:\n 'Default function \"nanoid\" accepts at most one size argument: `nanoid()` or `nanoid(<2-255>)`.',\n });\n }\n const size = parseIntegerArgument(input.call.args[0]?.raw ?? '');\n if (size !== undefined && size >= 2 && size <= 255) {\n return executionGenerator('nanoid', { size });\n }\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message: 'Default function \"nanoid\" size argument must be an integer between 2 and 255.',\n });\n}\n\n/**\n * SQLite spellings that all denote the same wall-clock-now value. Anything\n * matching this set when passed through `dbgenerated(\"...\")` is rewritten\n * to the canonical `now()` form before entering the contract — symmetric\n * with `parseSqliteDefault` on the introspection side, so the verifier\n * compares canonical-vs-canonical and a contract using\n * `dbgenerated(\"CURRENT_TIMESTAMP\")` doesn't drift against the schema it\n * just produced.\n */\nconst NOW_SYNONYMS = new Set(['current_timestamp', \"datetime('now')\", 'datetime(\"now\")', 'now()']);\n\nfunction lowerDbgenerated(input: {\n readonly call: ParsedDefaultFunctionCall;\n readonly context: DefaultFunctionLoweringContext;\n}): LoweredDefaultResult {\n if (input.call.args.length !== 1) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.span,\n message:\n 'Default function \"dbgenerated\" requires exactly one string argument: `dbgenerated(\"...\")`.',\n });\n }\n const rawExpression = parseStringLiteral(input.call.args[0]?.raw ?? '');\n if (rawExpression === undefined) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message: 'Default function \"dbgenerated\" argument must be a string literal.',\n });\n }\n const trimmed = rawExpression.trim();\n if (trimmed.length === 0) {\n return invalidArgumentDiagnostic({\n context: input.context,\n span: input.call.args[0]?.span ?? input.call.span,\n message: 'Default function \"dbgenerated\" argument cannot be empty.',\n });\n }\n const expression = NOW_SYNONYMS.has(trimmed.toLowerCase()) ? 'now()' : trimmed;\n return {\n ok: true,\n value: {\n kind: 'storage',\n defaultValue: {\n kind: 'function',\n expression,\n },\n },\n };\n}\n\nconst sqliteDefaultFunctionRegistryEntries = [\n ['autoincrement', { lower: lowerAutoincrement, usageSignatures: ['autoincrement()'] }],\n ['now', { lower: lowerNow, usageSignatures: ['now()'] }],\n ['uuid', { lower: lowerUuid, usageSignatures: ['uuid()', 'uuid(4)', 'uuid(7)'] }],\n ['cuid', { lower: lowerCuid, usageSignatures: ['cuid(2)'] }],\n ['ulid', { lower: lowerUlid, usageSignatures: ['ulid()'] }],\n ['nanoid', { lower: lowerNanoid, usageSignatures: ['nanoid()', 'nanoid(<2-255>)'] }],\n ['dbgenerated', { lower: lowerDbgenerated, usageSignatures: ['dbgenerated(\"...\")'] }],\n] satisfies ReadonlyArray<readonly [string, ControlMutationDefaultEntry]>;\n\nconst sqliteScalarTypeDescriptors = new Map<string, string>([\n ['String', SQLITE_TEXT_CODEC_ID],\n ['Int', SQLITE_INTEGER_CODEC_ID],\n ['BigInt', SQLITE_BIGINT_CODEC_ID],\n ['Float', SQLITE_REAL_CODEC_ID],\n ['Decimal', SQLITE_TEXT_CODEC_ID],\n ['DateTime', SQLITE_DATETIME_CODEC_ID],\n ['Json', SQLITE_JSON_CODEC_ID],\n ['Bytes', SQLITE_BLOB_CODEC_ID],\n]);\n\nexport function createSqliteDefaultFunctionRegistry(): ReadonlyMap<\n string,\n ControlMutationDefaultEntry\n> {\n return new Map(sqliteDefaultFunctionRegistryEntries);\n}\n\nexport function createSqliteMutationDefaultGeneratorDescriptors(): readonly MutationDefaultGeneratorDescriptor[] {\n return [\n ...builtinGeneratorRegistryMetadata.map(\n ({ id, applicableCodecIds }): MutationDefaultGeneratorDescriptor => ({\n id,\n applicableCodecIds,\n resolveGeneratedColumnDescriptor: ({ generated }) => {\n if (generated.kind !== 'generator' || generated.id !== id) {\n return undefined;\n }\n const descriptor = resolveBuiltinGeneratedColumnDescriptor({\n id,\n ...(generated.params ? { params: generated.params } : {}),\n });\n return {\n codecId: descriptor.type.codecId,\n nativeType: descriptor.type.nativeType,\n ...(descriptor.type.typeRef ? { typeRef: descriptor.type.typeRef } : {}),\n ...(descriptor.typeParams ? { typeParams: descriptor.typeParams } : {}),\n };\n },\n }),\n ),\n timestampNowControlDescriptor(),\n ];\n}\n\nexport function createSqliteScalarTypeDescriptors(): ReadonlyMap<string, string> {\n return new Map(sqliteScalarTypeDescriptors);\n}\n","import type { SqlControlAdapterDescriptor } from '@prisma-next/family-sql/control';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport { SqliteControlAdapter } from '../core/control-adapter';\nimport {\n createSqliteDefaultFunctionRegistry,\n createSqliteMutationDefaultGeneratorDescriptors,\n createSqliteScalarTypeDescriptors,\n} from '../core/control-mutation-defaults';\nimport { sqliteAdapterDescriptorMeta } from '../core/descriptor-meta';\n\nconst sqliteAdapterDescriptor: SqlControlAdapterDescriptor<'sqlite'> = {\n ...sqliteAdapterDescriptorMeta,\n scalarTypeDescriptors: createSqliteScalarTypeDescriptors(),\n controlMutationDefaults: {\n defaultFunctionRegistry: createSqliteDefaultFunctionRegistry(),\n generatorDescriptors: createSqliteMutationDefaultGeneratorDescriptors(),\n },\n create(stack): SqlControlAdapter<'sqlite'> {\n return new SqliteControlAdapter(stack.codecLookup);\n },\n};\n\nexport default sqliteAdapterDescriptor;\n\n// `parseSqliteDefault`, `normalizeSqliteNativeType`, `quoteIdentifier`,\n// `escapeLiteral`, and `SqlEscapeError` live target-side (one-way\n// `adapter → target` edge, matching Postgres). Re-exported from the\n// adapter so consumers — both internal and downstream — see the same\n// adapter-shaped surface across SQL targets.\nexport { parseSqliteDefault } from '@prisma-next/target-sqlite/default-normalizer';\nexport { normalizeSqliteNativeType } from '@prisma-next/target-sqlite/native-type-normalizer';\nexport {\n escapeLiteral,\n quoteIdentifier,\n SqlEscapeError,\n} from '@prisma-next/target-sqlite/sql-utils';\nexport { createSqliteBuiltinCodecLookup } from '../core/codec-lookup';\n// `SqlControlAdapterDescriptor` is declared in two places in the codebase\n// (`family-sql/control-adapter` and `family-sql/migrations/types`); the\n// migrations-side declaration narrows `create()`'s return type to the base\n// `ControlAdapterInstance`, hiding `introspect`/`readMarker`. Until that's\n// reconciled upstream, downstream consumers (e2e harness, integration\n// tests) need direct access to the concrete class. Mirrors how Postgres'\n// own package tests import `PostgresControlAdapter` directly.\nexport { SqliteControlAdapter } from '../core/control-adapter';\n"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { sqliteCodecRegistry } from "@prisma-next/target-sqlite/codecs";
2
+ const sqliteAdapterDescriptorMeta = {
3
+ kind: "adapter",
4
+ familyId: "sql",
5
+ targetId: "sqlite",
6
+ id: "sqlite",
7
+ version: "0.0.1",
8
+ capabilities: { sql: {
9
+ orderBy: true,
10
+ limit: true,
11
+ lateral: false,
12
+ jsonAgg: true,
13
+ returning: true,
14
+ foreignKeys: true,
15
+ enums: false
16
+ } },
17
+ types: { codecTypes: {
18
+ codecDescriptors: Array.from(sqliteCodecRegistry.values()).filter((d) => d.renderOutputType === void 0),
19
+ import: {
20
+ package: "@prisma-next/adapter-sqlite/codec-types",
21
+ named: "CodecTypes",
22
+ alias: "SqliteTypes"
23
+ }
24
+ } }
25
+ };
26
+ //#endregion
27
+ export { sqliteAdapterDescriptorMeta as t };
28
+
29
+ //# sourceMappingURL=descriptor-meta-pA9TOBa7.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor-meta-pA9TOBa7.mjs","names":[],"sources":["../src/core/descriptor-meta.ts"],"sourcesContent":["import { sqliteCodecRegistry } from '@prisma-next/target-sqlite/codecs';\n\n// Exclude codecs that carry a renderOutputType: those emit named TypeScript types (e.g.\n// Char<N>, Varchar<N>) that are not listed in this adapter's typeImports and would\n// produce unresolvable references in contract.d.ts. All other codecs — including the\n// sql/ identity encoders (sql/int@1, sql/float@1) — are kept so execution codec\n// lookup works and DDL lowering has access to the full codec set.\nconst executionCodecDescriptors = Array.from(sqliteCodecRegistry.values()).filter(\n (d) => d.renderOutputType === undefined,\n);\n\nexport const sqliteAdapterDescriptorMeta = {\n kind: 'adapter',\n familyId: 'sql',\n targetId: 'sqlite',\n id: 'sqlite',\n version: '0.0.1',\n capabilities: {\n sql: {\n orderBy: true,\n limit: true,\n lateral: false,\n jsonAgg: true,\n returning: true,\n foreignKeys: true,\n enums: false,\n },\n },\n types: {\n codecTypes: {\n codecDescriptors: executionCodecDescriptors,\n import: {\n package: '@prisma-next/adapter-sqlite/codec-types',\n named: 'CodecTypes',\n alias: 'SqliteTypes',\n },\n },\n },\n} as const;\n"],"mappings":";AAWA,MAAa,8BAA8B;CACzC,MAAM;CACN,UAAU;CACV,UAAU;CACV,IAAI;CACJ,SAAS;CACT,cAAc,EACZ,KAAK;EACH,SAAS;EACT,OAAO;EACP,SAAS;EACT,SAAS;EACT,WAAW;EACX,aAAa;EACb,OAAO;CACT,EACF;CACA,OAAO,EACL,YAAY;EACV,kBAvB4B,MAAM,KAAK,oBAAoB,OAAO,CAAC,CAAC,CAAC,QACxE,MAAM,EAAE,qBAAqB,KAAA,CAsBR;EAClB,QAAQ;GACN,SAAS;GACT,OAAO;GACP,OAAO;EACT;CACF,EACF;AACF"}
package/dist/runtime.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { n as sqliteRawCodecInferer, t as createSqliteAdapter } from "./adapter-DCwhDr2I.mjs";
2
- import { t as sqliteAdapterDescriptorMeta } from "./descriptor-meta-Du5OgSxS.mjs";
1
+ import { n as sqliteRawCodecInferer, t as createSqliteAdapter } from "./adapter-eo1yL7gA.mjs";
2
+ import { t as sqliteAdapterDescriptorMeta } from "./descriptor-meta-pA9TOBa7.mjs";
3
3
  import { sqliteCodecRegistry } from "@prisma-next/target-sqlite/codecs";
4
4
  import { builtinGeneratorIds } from "@prisma-next/ids";
5
5
  import { timestampNowRuntimeGenerator } from "@prisma-next/family-sql/runtime";
package/package.json CHANGED
@@ -1,34 +1,34 @@
1
1
  {
2
2
  "name": "@prisma-next/adapter-sqlite",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "dependencies": {
8
- "@prisma-next/cli": "0.13.0",
9
- "@prisma-next/contract": "0.13.0",
10
- "@prisma-next/contract-authoring": "0.13.0",
11
- "@prisma-next/errors": "0.13.0",
12
- "@prisma-next/framework-components": "0.13.0",
13
- "@prisma-next/family-sql": "0.13.0",
14
- "@prisma-next/ids": "0.13.0",
15
- "@prisma-next/sql-contract": "0.13.0",
16
- "@prisma-next/sql-contract-psl": "0.13.0",
17
- "@prisma-next/sql-contract-ts": "0.13.0",
18
- "@prisma-next/sql-operations": "0.13.0",
19
- "@prisma-next/sql-relational-core": "0.13.0",
20
- "@prisma-next/sql-runtime": "0.13.0",
21
- "@prisma-next/sql-schema-ir": "0.13.0",
22
- "@prisma-next/target-sqlite": "0.13.0",
23
- "@prisma-next/utils": "0.13.0",
8
+ "@prisma-next/cli": "0.14.0",
9
+ "@prisma-next/contract": "0.14.0",
10
+ "@prisma-next/contract-authoring": "0.14.0",
11
+ "@prisma-next/errors": "0.14.0",
12
+ "@prisma-next/framework-components": "0.14.0",
13
+ "@prisma-next/family-sql": "0.14.0",
14
+ "@prisma-next/ids": "0.14.0",
15
+ "@prisma-next/sql-contract": "0.14.0",
16
+ "@prisma-next/sql-contract-psl": "0.14.0",
17
+ "@prisma-next/sql-contract-ts": "0.14.0",
18
+ "@prisma-next/sql-operations": "0.14.0",
19
+ "@prisma-next/sql-relational-core": "0.14.0",
20
+ "@prisma-next/sql-runtime": "0.14.0",
21
+ "@prisma-next/sql-schema-ir": "0.14.0",
22
+ "@prisma-next/target-sqlite": "0.14.0",
23
+ "@prisma-next/utils": "0.14.0",
24
24
  "arktype": "^2.2.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@prisma-next/driver-sqlite": "0.13.0",
28
- "@prisma-next/migration-tools": "0.13.0",
29
- "@prisma-next/test-utils": "0.13.0",
30
- "@prisma-next/tsconfig": "0.13.0",
31
- "@prisma-next/tsdown": "0.13.0",
27
+ "@prisma-next/driver-sqlite": "0.14.0",
28
+ "@prisma-next/migration-tools": "0.14.0",
29
+ "@prisma-next/test-utils": "0.14.0",
30
+ "@prisma-next/tsconfig": "0.14.0",
31
+ "@prisma-next/tsdown": "0.14.0",
32
32
  "pathe": "^2.0.3",
33
33
  "tsdown": "0.22.1",
34
34
  "typescript": "5.9.3",
@@ -67,7 +67,7 @@
67
67
  "build": "tsdown",
68
68
  "test": "vitest run",
69
69
  "test:coverage": "vitest run --coverage",
70
- "typecheck": "tsc --project tsconfig.json --noEmit",
70
+ "typecheck": "tsc --project tsconfig.json --noEmit && tsc --project tsconfig.test.json --noEmit",
71
71
  "lint": "biome check . --error-on-warnings",
72
72
  "lint:fix": "biome check --write .",
73
73
  "lint:fix:unsafe": "biome check --write --unsafe .",
@@ -36,8 +36,8 @@ import { isDdlNode } from '@prisma-next/sql-relational-core/ast';
36
36
  import type { RawCodecInferer } from '@prisma-next/sql-relational-core/expression';
37
37
  import type { SqliteDdlNode } from '@prisma-next/target-sqlite/ddl';
38
38
  import { escapeLiteral, quoteIdentifier } from '@prisma-next/target-sqlite/sql-utils';
39
+ import { createSqliteBuiltinCodecLookup } from './codec-lookup';
39
40
  import { SqliteControlAdapter } from './control-adapter';
40
- import { renderLoweredDdl } from './ddl-renderer';
41
41
  import type { SqliteAdapterOptions, SqliteContract, SqliteLoweredStatement } from './types';
42
42
 
43
43
  const defaultCapabilities = Object.freeze({
@@ -58,7 +58,8 @@ class SqliteAdapterImpl implements Adapter<AnyQueryAst, SqliteContract, SqliteLo
58
58
  readonly profile: AdapterProfile<'sqlite'>;
59
59
 
60
60
  constructor(options?: SqliteAdapterOptions) {
61
- const controlAdapter = new SqliteControlAdapter();
61
+ const codecLookup = createSqliteBuiltinCodecLookup();
62
+ const controlAdapter = new SqliteControlAdapter(codecLookup);
62
63
  this.profile = Object.freeze({
63
64
  id: options?.profileId ?? 'sqlite/default@1',
64
65
  target: 'sqlite',
@@ -87,7 +88,9 @@ class SqliteAdapterImpl implements Adapter<AnyQueryAst, SqliteContract, SqliteLo
87
88
  context: LowererContext<SqliteContract>,
88
89
  ): SqliteLoweredStatement {
89
90
  if (isDdlNode(ast)) {
90
- return renderLoweredDdl(ast);
91
+ throw new Error(
92
+ 'lower() does not lower DDL on the runtime adapter — DDL lowering is a control-plane concern handled by the control adapter.',
93
+ );
91
94
  }
92
95
  return renderLoweredSql(ast, context.contract);
93
96
  }
@@ -171,7 +174,7 @@ function renderLimitOffset(
171
174
  function renderSelect(ast: SelectAst, contract: SqliteContract): string {
172
175
  const distinctPrefix = ast.distinct ? 'DISTINCT ' : '';
173
176
  const selectClause = `SELECT ${distinctPrefix}${renderProjection(ast.projection, contract)}`;
174
- const fromClause = `FROM ${renderSource(ast.from, contract)}`;
177
+ const fromClause = ast.from !== undefined ? `FROM ${renderSource(ast.from, contract)}` : '';
175
178
 
176
179
  const joinsClause = ast.joins?.length
177
180
  ? ast.joins.map((join) => renderJoin(join, contract)).join(' ')
@@ -258,8 +261,15 @@ function renderSource(source: AnyFromSource, contract: SqliteContract): string {
258
261
  return renderTableSource(node, contract);
259
262
  case 'derived-table-source':
260
263
  return `(${renderSelect(node.query, contract)}) AS ${quoteIdentifier(node.alias)}`;
264
+ case 'function-source': {
265
+ const args = node.args.map((arg) => renderExpr(arg, contract)).join(', ');
266
+ const call = `${node.fn}(${args})`;
267
+ return node.alias !== undefined ? `${call} AS ${quoteIdentifier(node.alias)}` : call;
268
+ }
261
269
  default:
262
- throw new Error(`Unsupported source node kind: ${(node as { kind: string }).kind}`);
270
+ throw new Error(
271
+ `Unsupported source node kind: ${(node satisfies never as { kind: string }).kind}`,
272
+ );
263
273
  }
264
274
  }
265
275
 
@@ -0,0 +1,21 @@
1
+ import type { CodecRegistry } from '@prisma-next/framework-components/codec';
2
+ import { extractCodecLookup } from '@prisma-next/framework-components/control';
3
+ import { sqliteCodecRegistry } from '@prisma-next/target-sqlite/codecs';
4
+
5
+ /**
6
+ * Build a {@link CodecRegistry} populated with the SQLite-builtin codec definitions only.
7
+ *
8
+ * Used by `createSqliteAdapter()` and `new SqliteControlAdapter()` when called without a
9
+ * stack-derived registry (e.g. from tests, or one-off scripts that don't compose a full stack).
10
+ *
11
+ * Extension codecs are intentionally NOT included: a bare adapter cannot see extensions.
12
+ * Stack-composed paths supply the broader, extension-inclusive registry at construction time.
13
+ */
14
+ export function createSqliteBuiltinCodecLookup(): CodecRegistry {
15
+ return extractCodecLookup([
16
+ {
17
+ id: 'sqlite-builtin-codecs',
18
+ types: { codecTypes: { codecDescriptors: Array.from(sqliteCodecRegistry.values()) } },
19
+ },
20
+ ]);
21
+ }
@@ -2,15 +2,24 @@ import type { ContractMarkerRecord, LedgerEntryRecord } from '@prisma-next/contr
2
2
  import { parseMarkerRowSafely, withMarkerReadErrorHandling } from '@prisma-next/errors/execution';
3
3
  import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
4
4
  import { parseContractMarkerRow } from '@prisma-next/family-sql/verify';
5
+ import type { CodecLookup, CodecRegistry } from '@prisma-next/framework-components/codec';
5
6
  import { APP_SPACE_ID } from '@prisma-next/framework-components/control';
6
7
  import { ledgerOriginFromStored } from '@prisma-next/migration-tools/ledger-origin';
8
+ import { REFERENTIAL_ACTION_SQL } from '@prisma-next/sql-contract/referential-action-sql';
7
9
  import type { SqlControlDriverInstance } from '@prisma-next/sql-contract/types';
8
10
  import type {
9
11
  AnyQueryAst,
12
+ CodecRef,
13
+ ContractCodecRegistry,
14
+ DdlColumn,
10
15
  DdlNode,
16
+ DdlTableConstraint,
17
+ FunctionColumnDefault,
18
+ LiteralColumnDefault,
11
19
  LoweredStatement,
12
20
  LowererContext,
13
21
  MarkerReadResult,
22
+ SqlExecuteRequest,
14
23
  } from '@prisma-next/sql-relational-core/ast';
15
24
  import { isDdlNode } from '@prisma-next/sql-relational-core/ast';
16
25
  import type {
@@ -27,13 +36,14 @@ import {
27
36
  buildControlTableBootstrapQueries,
28
37
  buildSignMarkerBootstrapQueries,
29
38
  } from '@prisma-next/target-sqlite/contract-free';
30
- import type { SqliteDdlNode } from '@prisma-next/target-sqlite/ddl';
39
+ import type { SqliteCreateTable, SqliteDdlNode } from '@prisma-next/target-sqlite/ddl';
31
40
  import { parseSqliteDefault } from '@prisma-next/target-sqlite/default-normalizer';
32
41
  import { normalizeSqliteNativeType } from '@prisma-next/target-sqlite/native-type-normalizer';
42
+ import { escapeLiteral, quoteIdentifier } from '@prisma-next/target-sqlite/sql-utils';
33
43
  import { blindCast } from '@prisma-next/utils/casts';
34
44
  import { ifDefined } from '@prisma-next/utils/defined';
35
45
  import { renderLoweredSql } from './adapter';
36
- import { renderLoweredDdl } from './ddl-renderer';
46
+ import { encodeControlQueryParams } from './control-codecs';
37
47
  import { coerceLedgerAppliedAt, operationCountFromStored } from './ledger-decode';
38
48
  import {
39
49
  decodeSqliteMarkerRow,
@@ -106,6 +116,12 @@ export class SqliteControlAdapter implements SqlControlAdapter<'sqlite'> {
106
116
  readonly familyId = 'sql' as const;
107
117
  readonly targetId = 'sqlite' as const;
108
118
 
119
+ private readonly codecRegistry: CodecRegistry;
120
+
121
+ constructor(codecRegistry: CodecRegistry) {
122
+ this.codecRegistry = codecRegistry;
123
+ }
124
+
109
125
  readonly normalizeDefault = parseSqliteDefault;
110
126
  readonly normalizeNativeType = normalizeSqliteNativeType;
111
127
 
@@ -127,9 +143,43 @@ export class SqliteControlAdapter implements SqlControlAdapter<'sqlite'> {
127
143
  */
128
144
  lower(ast: AnyQueryAst | SqliteDdlNode, context: LowererContext<unknown>): LoweredStatement {
129
145
  if (isDdlNode(ast)) {
130
- return renderLoweredDdl(ast);
146
+ throw new Error(
147
+ 'lower() cannot lower DDL: DDL default literals require inline codec encoding, which is async. Use lowerToExecuteRequest().',
148
+ );
131
149
  }
132
- return renderLoweredSql(ast, context.contract as SqliteContract);
150
+ return renderLoweredSql(
151
+ ast,
152
+ blindCast<SqliteContract, 'caller must supply a matching SqliteContract'>(context.contract),
153
+ );
154
+ }
155
+
156
+ /**
157
+ * Lower an AST all the way to a driver-ready statement. For DDL nodes,
158
+ * literal column defaults are formatted as inline SQL with SQLite-specific
159
+ * literal syntax (no cast suffix, boolean as 0/1, blob via X'hex'). For
160
+ * query ASTs, params are kept as `?` placeholders; wire values go in
161
+ * `params`. Does NOT call `this.lower()` — independent implementation.
162
+ */
163
+ async lowerToExecuteRequest(
164
+ ast: AnyQueryAst | SqliteDdlNode,
165
+ context?: LowererContext<unknown>,
166
+ ): Promise<SqlExecuteRequest> {
167
+ if (isDdlNode(ast)) {
168
+ return sqliteRenderDdlExecuteRequest(
169
+ blindCast<SqliteDdlNode, 'isDdlNode guard'>(ast),
170
+ this.codecRegistry,
171
+ );
172
+ }
173
+ const contract = blindCast<SqliteContract, 'Caller must supply matching contract'>(
174
+ context?.contract,
175
+ );
176
+ const lowered = renderLoweredSql(ast, contract);
177
+ const codecRegistry = blindCast<
178
+ ContractCodecRegistry,
179
+ 'framework CodecRegistry: its descriptors materialise SQL codecs; the framework Codec type erases to BaseCodec at this boundary'
180
+ >(this.codecRegistry);
181
+ const params = await encodeControlQueryParams(lowered, ast, codecRegistry);
182
+ return { sql: lowered.sql, params };
133
183
  }
134
184
 
135
185
  /**
@@ -582,3 +632,126 @@ function mapSqliteReferentialAction(rule: string): SqlReferentialAction | undefi
582
632
  if (mapped === 'noAction') return undefined;
583
633
  return mapped;
584
634
  }
635
+
636
+ // ---------------------------------------------------------------------------
637
+ // sqliteRenderDdlExecuteRequest — independent DDL walker for lowerToExecuteRequest
638
+ // ---------------------------------------------------------------------------
639
+
640
+ function sqliteInlineLiteral(wire: unknown): string {
641
+ if (wire === null) return 'NULL';
642
+ if (typeof wire === 'boolean') return wire ? '1' : '0';
643
+ if (typeof wire === 'number') {
644
+ if (!Number.isFinite(wire)) {
645
+ throw new Error(
646
+ `sqliteRenderDdlExecuteRequest: non-finite number wire value ${String(wire)} cannot be emitted as a DEFAULT literal`,
647
+ );
648
+ }
649
+ return String(wire);
650
+ }
651
+ if (typeof wire === 'bigint') return String(wire);
652
+ if (wire instanceof Date) {
653
+ if (Number.isNaN(wire.getTime())) {
654
+ throw new Error(
655
+ 'sqliteRenderDdlExecuteRequest: invalid Date value cannot be emitted as a DEFAULT literal',
656
+ );
657
+ }
658
+ return `'${escapeLiteral(wire.toISOString())}'`;
659
+ }
660
+ if (typeof wire === 'string') return `'${escapeLiteral(wire)}'`;
661
+ if (wire instanceof Uint8Array) {
662
+ const hex = Array.from(wire)
663
+ .map((b) => b.toString(16).padStart(2, '0'))
664
+ .join('');
665
+ return `X'${hex}'`;
666
+ }
667
+ if (typeof wire === 'object') return `'${escapeLiteral(JSON.stringify(wire))}'`;
668
+ throw new Error(`sqliteRenderDdlExecuteRequest: unexpected wire type "${typeof wire}"`);
669
+ }
670
+
671
+ async function sqliteRenderDdlColumnDefault(
672
+ def: LiteralColumnDefault | FunctionColumnDefault,
673
+ codecLookup: CodecLookup,
674
+ codecRef: CodecRef | undefined,
675
+ ): Promise<string> {
676
+ if (def.kind === 'function') {
677
+ if (def.expression === 'autoincrement()') return '';
678
+ // SQLite has no `now()` function; the contract canonicalizes
679
+ // `CURRENT_TIMESTAMP` / `datetime('now')` to `now()`, so map it back to a
680
+ // valid SQLite expression on the way out.
681
+ if (def.expression === 'now()') return "DEFAULT (datetime('now'))";
682
+ return `DEFAULT (${def.expression})`;
683
+ }
684
+ if (codecRef !== undefined) {
685
+ const codec = codecLookup.get(codecRef.codecId);
686
+ if (codec !== undefined) {
687
+ const wire = await codec.encode(def.value, {});
688
+ return `DEFAULT ${sqliteInlineLiteral(wire)}`;
689
+ }
690
+ }
691
+ // Fallback: codec-less literal defaults follow RawSqlLiteral wire-scalar semantics.
692
+ return `DEFAULT ${sqliteInlineLiteral(def.value)}`;
693
+ }
694
+
695
+ async function sqliteRenderDdlColumn(column: DdlColumn, codecLookup: CodecLookup): Promise<string> {
696
+ if (column.type.includes('AUTOINCREMENT')) {
697
+ return `${quoteIdentifier(column.name)} ${column.type}`;
698
+ }
699
+ const parts = [quoteIdentifier(column.name), column.type];
700
+ if (column.notNull) parts.push('NOT NULL');
701
+ if (column.primaryKey) parts.push('PRIMARY KEY');
702
+ if (column.default) {
703
+ const clause = await sqliteRenderDdlColumnDefault(column.default, codecLookup, column.codecRef);
704
+ if (clause.length > 0) parts.push(clause);
705
+ }
706
+ return parts.join(' ');
707
+ }
708
+
709
+ function sqliteRenderDdlConstraint(constraint: DdlTableConstraint): string {
710
+ if (constraint.kind === 'primary-key') {
711
+ const cols = constraint.columns.map(quoteIdentifier).join(', ');
712
+ if (constraint.name !== undefined) {
713
+ return `CONSTRAINT ${quoteIdentifier(constraint.name)} PRIMARY KEY (${cols})`;
714
+ }
715
+ return `PRIMARY KEY (${cols})`;
716
+ }
717
+ if (constraint.kind === 'foreign-key') {
718
+ const cols = constraint.columns.map(quoteIdentifier).join(', ');
719
+ const refTable = constraint.refTable.split('.').map(quoteIdentifier).join('.');
720
+ const refCols = constraint.refColumns.map(quoteIdentifier).join(', ');
721
+ let sql = `FOREIGN KEY (${cols}) REFERENCES ${refTable} (${refCols})`;
722
+ if (constraint.onDelete !== undefined) {
723
+ sql += ` ON DELETE ${REFERENTIAL_ACTION_SQL[constraint.onDelete]}`;
724
+ }
725
+ if (constraint.onUpdate !== undefined) {
726
+ sql += ` ON UPDATE ${REFERENTIAL_ACTION_SQL[constraint.onUpdate]}`;
727
+ }
728
+ if (constraint.name !== undefined) {
729
+ sql = `CONSTRAINT ${quoteIdentifier(constraint.name)} ${sql}`;
730
+ }
731
+ return sql;
732
+ }
733
+ const cols = constraint.columns.map(quoteIdentifier).join(', ');
734
+ if (constraint.name !== undefined) {
735
+ return `CONSTRAINT ${quoteIdentifier(constraint.name)} UNIQUE (${cols})`;
736
+ }
737
+ return `UNIQUE (${cols})`;
738
+ }
739
+
740
+ async function sqliteRenderDdlExecuteRequest(
741
+ ast: SqliteDdlNode,
742
+ codecLookup: CodecLookup,
743
+ ): Promise<SqlExecuteRequest> {
744
+ const node = blindCast<SqliteCreateTable, 'SQLite DDL only has create-table'>(ast);
745
+ const ifNotExists = node.ifNotExists ? 'IF NOT EXISTS ' : '';
746
+ const tableRef = quoteIdentifier(node.table);
747
+ const columnDefs = await Promise.all(
748
+ node.columns.map((col) => sqliteRenderDdlColumn(col, codecLookup)),
749
+ );
750
+ const constraintDefs =
751
+ node.constraints !== undefined ? node.constraints.map(sqliteRenderDdlConstraint) : [];
752
+ const allDefs = [...columnDefs, ...constraintDefs].join(',\n ');
753
+ return {
754
+ sql: `CREATE TABLE ${ifNotExists}${tableRef} (\n ${allDefs}\n)`,
755
+ params: [],
756
+ };
757
+ }
@@ -0,0 +1,25 @@
1
+ import type {
2
+ AnyQueryAst,
3
+ ContractCodecRegistry,
4
+ LoweredStatement,
5
+ } from '@prisma-next/sql-relational-core/ast';
6
+ import {
7
+ createAstCodecRegistry,
8
+ deriveParamMetadata,
9
+ encodeParamsWithMetadata,
10
+ } from '@prisma-next/sql-runtime';
11
+ import { sqliteCodecRegistry } from '@prisma-next/target-sqlite/codecs';
12
+
13
+ export const CONTROL_CODECS = createAstCodecRegistry(sqliteCodecRegistry);
14
+
15
+ export async function encodeControlQueryParams(
16
+ lowered: LoweredStatement,
17
+ ast: AnyQueryAst,
18
+ codecs: ContractCodecRegistry = CONTROL_CODECS,
19
+ ): Promise<readonly unknown[]> {
20
+ const values = lowered.params.map((slot) => {
21
+ if (slot.kind === 'literal') return slot.value;
22
+ throw new Error(`control query lowered to a bind slot '${slot.name}', which is unsupported`);
23
+ });
24
+ return encodeParamsWithMetadata(values, deriveParamMetadata(ast), {}, codecs);
25
+ }
@@ -1,3 +1,14 @@
1
+ import { sqliteCodecRegistry } from '@prisma-next/target-sqlite/codecs';
2
+
3
+ // Exclude codecs that carry a renderOutputType: those emit named TypeScript types (e.g.
4
+ // Char<N>, Varchar<N>) that are not listed in this adapter's typeImports and would
5
+ // produce unresolvable references in contract.d.ts. All other codecs — including the
6
+ // sql/ identity encoders (sql/int@1, sql/float@1) — are kept so execution codec
7
+ // lookup works and DDL lowering has access to the full codec set.
8
+ const executionCodecDescriptors = Array.from(sqliteCodecRegistry.values()).filter(
9
+ (d) => d.renderOutputType === undefined,
10
+ );
11
+
1
12
  export const sqliteAdapterDescriptorMeta = {
2
13
  kind: 'adapter',
3
14
  familyId: 'sql',
@@ -17,6 +28,7 @@ export const sqliteAdapterDescriptorMeta = {
17
28
  },
18
29
  types: {
19
30
  codecTypes: {
31
+ codecDescriptors: executionCodecDescriptors,
20
32
  import: {
21
33
  package: '@prisma-next/adapter-sqlite/codec-types',
22
34
  named: 'CodecTypes',
@@ -4,13 +4,7 @@ import {
4
4
  type LoweredStatement,
5
5
  RawExpr,
6
6
  } from '@prisma-next/sql-relational-core/ast';
7
- import {
8
- createAstCodecRegistry,
9
- deriveParamMetadata,
10
- encodeParamsWithMetadata,
11
- } from '@prisma-next/sql-runtime';
12
7
  import { SQLITE_DATETIME_CODEC_ID } from '@prisma-next/target-sqlite/codec-ids';
13
- import { sqliteCodecRegistry } from '@prisma-next/target-sqlite/codecs';
14
8
  import {
15
9
  datetime,
16
10
  integer,
@@ -18,8 +12,7 @@ import {
18
12
  sqliteTable,
19
13
  text,
20
14
  } from '@prisma-next/target-sqlite/contract-free';
21
-
22
- const CONTROL_CODECS = createAstCodecRegistry(sqliteCodecRegistry);
15
+ import { encodeControlQueryParams } from './control-codecs';
23
16
 
24
17
  export const marker = sqliteTable('_prisma_marker', {
25
18
  space: text(),
@@ -91,16 +84,7 @@ export async function execute(
91
84
  query: AnyQueryAst,
92
85
  ): Promise<readonly Record<string, unknown>[]> {
93
86
  const lowered = lower(query);
94
- const values = lowered.params.map((slot) => {
95
- if (slot.kind === 'literal') return slot.value;
96
- throw new Error('SQLite control DML lowered to a bind parameter, which is unsupported');
97
- });
98
- const encoded = await encodeParamsWithMetadata(
99
- values,
100
- deriveParamMetadata(query),
101
- {},
102
- CONTROL_CODECS,
103
- );
87
+ const encoded = await encodeControlQueryParams(lowered, query);
104
88
  const result = await driver.query(lowered.sql, encoded);
105
89
  return result.rows;
106
90
  }
@@ -15,8 +15,8 @@ const sqliteAdapterDescriptor: SqlControlAdapterDescriptor<'sqlite'> = {
15
15
  defaultFunctionRegistry: createSqliteDefaultFunctionRegistry(),
16
16
  generatorDescriptors: createSqliteMutationDefaultGeneratorDescriptors(),
17
17
  },
18
- create(): SqlControlAdapter<'sqlite'> {
19
- return new SqliteControlAdapter();
18
+ create(stack): SqlControlAdapter<'sqlite'> {
19
+ return new SqliteControlAdapter(stack.codecLookup);
20
20
  },
21
21
  };
22
22
 
@@ -34,7 +34,7 @@ export {
34
34
  quoteIdentifier,
35
35
  SqlEscapeError,
36
36
  } from '@prisma-next/target-sqlite/sql-utils';
37
-
37
+ export { createSqliteBuiltinCodecLookup } from '../core/codec-lookup';
38
38
  // `SqlControlAdapterDescriptor` is declared in two places in the codebase
39
39
  // (`family-sql/control-adapter` and `family-sql/migrations/types`); the
40
40
  // migrations-side declaration narrows `create()`'s return type to the base