@prisma-next/sql-contract 0.13.0-dev.3 → 0.13.0-dev.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/factories.d.mts +2 -2
- package/dist/factories.mjs +1 -1
- package/dist/index-type-validation.d.mts +1 -1
- package/dist/index-type-validation.mjs +8 -11
- package/dist/index-type-validation.mjs.map +1 -1
- package/dist/resolve-storage-table.d.mts +1 -1
- package/dist/resolve-storage-table.d.mts.map +1 -1
- package/dist/resolve-storage-table.mjs +11 -8
- package/dist/resolve-storage-table.mjs.map +1 -1
- package/dist/{sql-storage-CXf9xjAL.d.mts → sql-storage-BCLmt-nS.d.mts} +30 -20
- package/dist/{sql-storage-CXf9xjAL.d.mts.map → sql-storage-BCLmt-nS.d.mts.map} +1 -1
- package/dist/{types-DqhaAjCH.mjs → types-B7kJ6S7m.mjs} +42 -50
- package/dist/types-B7kJ6S7m.mjs.map +1 -0
- package/dist/{types-DEnWD3xB.d.mts → types-CFpK1iC5.d.mts} +6 -59
- package/dist/types-CFpK1iC5.d.mts.map +1 -0
- package/dist/types.d.mts +3 -3
- package/dist/types.mjs +2 -2
- package/dist/validators.d.mts +29 -28
- package/dist/validators.d.mts.map +1 -1
- package/dist/validators.mjs +71 -95
- package/dist/validators.mjs.map +1 -1
- package/package.json +7 -7
- package/src/exports/types.ts +2 -4
- package/src/index-type-validation.ts +2 -3
- package/src/ir/build-sql-namespace.ts +62 -32
- package/src/ir/sql-node.ts +2 -2
- package/src/ir/sql-storage.ts +22 -24
- package/src/ir/sql-unbound-namespace.ts +15 -3
- package/src/ir/storage-type-instance.ts +3 -3
- package/src/ir/storage-value-set.ts +6 -5
- package/src/resolve-storage-table.ts +12 -17
- package/src/types.ts +2 -6
- package/src/validators.ts +93 -113
- package/dist/types-DEnWD3xB.d.mts.map +0 -1
- package/dist/types-DqhaAjCH.mjs.map +0 -1
- package/src/ir/postgres-enum-storage-entry.ts +0 -57
package/dist/validators.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validators.mjs","names":["f","referencedTable"],"sources":["../src/validators.ts"],"sourcesContent":["import { ContractValidationError } from '@prisma-next/contract/contract-validation-error';\nimport {\n type Contract,\n type ContractField,\n type ContractModel,\n CrossReferenceSchema,\n} from '@prisma-next/contract/types';\nimport { validateContractDomain } from '@prisma-next/contract/validate-domain';\nimport { type Namespace, UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { type Type, type } from 'arktype';\nimport { buildSqlNamespaceMap } from './ir/build-sql-namespace';\nimport { SqlUnboundNamespace } from './ir/sql-unbound-namespace';\nimport {\n type ForeignKeyInput,\n type ForeignKeyReferenceInput,\n type PrimaryKeyInput,\n type ReferentialAction,\n type SqlModelStorage,\n SqlStorage,\n type SqlStorageInput,\n type StorageTable,\n type StorageTypeInstanceInput,\n type UniqueConstraintInput,\n} from './types';\n\ntype ColumnDefaultLiteral = {\n readonly kind: 'literal';\n readonly value: string | number | boolean | Record<string, unknown> | unknown[] | null;\n};\ntype ColumnDefaultFunction = { readonly kind: 'function'; readonly expression: string };\nconst literalKindSchema = type(\"'literal'\");\nconst functionKindSchema = type(\"'function'\");\nconst generatorKindSchema = type(\"'generator'\");\nconst ControlPolicySchema = type(\"'managed' | 'tolerated' | 'external' | 'observed'\");\nconst generatorIdSchema = type('string').narrow((value, ctx) => {\n return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value) ? true : ctx.mustBe('a flat generator id');\n});\n\nexport const ColumnDefaultLiteralSchema = type.declare<ColumnDefaultLiteral>().type({\n kind: literalKindSchema,\n value: 'string | number | boolean | null | unknown[] | Record<string, unknown>',\n});\n\nexport const ColumnDefaultFunctionSchema = type.declare<ColumnDefaultFunction>().type({\n kind: functionKindSchema,\n expression: 'string',\n});\n\nexport const ColumnDefaultSchema = ColumnDefaultLiteralSchema.or(ColumnDefaultFunctionSchema);\n\nconst ExecutionMutationDefaultValueSchema = type({\n '+': 'reject',\n kind: generatorKindSchema,\n id: generatorIdSchema,\n 'params?': 'Record<string, unknown>',\n});\n\nconst ExecutionMutationDefaultSchema = type({\n '+': 'reject',\n ref: {\n '+': 'reject',\n table: 'string',\n column: 'string',\n },\n 'onCreate?': ExecutionMutationDefaultValueSchema,\n 'onUpdate?': ExecutionMutationDefaultValueSchema,\n});\n\nconst ExecutionSchema = type({\n '+': 'reject',\n executionHash: 'string',\n mutations: {\n '+': 'reject',\n defaults: ExecutionMutationDefaultSchema.array().readonly(),\n },\n});\n\nconst ValueSetRefSchema = type({\n plane: \"'domain' | 'storage'\",\n namespaceId: 'string',\n entityKind: \"'enum' | 'value-set'\",\n name: 'string',\n 'spaceId?': 'string',\n});\n\nconst StorageColumnSchema = type({\n '+': 'reject',\n nativeType: 'string',\n codecId: 'string',\n nullable: 'boolean',\n 'typeParams?': 'Record<string, unknown>',\n 'typeRef?': 'string',\n 'default?': ColumnDefaultSchema,\n 'control?': ControlPolicySchema,\n 'valueSet?': ValueSetRefSchema,\n}).narrow((col, ctx) => {\n if (col.typeParams !== undefined && col.typeRef !== undefined) {\n return ctx.mustBe('a column with either typeParams or typeRef, not both');\n }\n return true;\n});\n\n/**\n * Codec-triple entry persisted under `storage.types[name]`. Carries an\n * enumerable literal `kind: 'codec-instance'` discriminator so the\n * polymorphic slot dispatch can distinguish codec triples from\n * class-instance kinds (e.g. `'postgres-enum'`) sharing the slot.\n */\nconst StorageTypeInstanceSchema = type\n .declare<StorageTypeInstanceInput & { kind: 'codec-instance' }>()\n .type({\n kind: \"'codec-instance'\",\n codecId: 'string',\n nativeType: 'string',\n 'typeParams?': 'Record<string, unknown>',\n });\n\n/**\n * Postgres native enum entry under `storage.namespaces[namespaceId].entries.type[name]`.\n * Document-scoped `storage.types` carries codec aliases only\n * (`DocumentScopedStorageTypeSchema`).\n */\nconst PostgresEnumTypeSchema = type({\n kind: \"'postgres-enum'\",\n 'name?': 'string',\n 'nativeType?': 'string',\n values: type.string.array().readonly(),\n 'control?': ControlPolicySchema,\n});\n\n/** Document-scoped `storage.types`: codec triples only. */\nconst DocumentScopedStorageTypeSchema = StorageTypeInstanceSchema;\n\n/**\n * Storage value-set entry under `storage.namespaces[id].entries.valueSet[name]`.\n * Carries a `kind: 'value-set'` discriminator (enumerable, survives JSON) and an\n * ordered `values` array of codec-encoded permitted values.\n */\nexport const StorageValueSetSchema = type({\n kind: \"'value-set'\",\n values: type.string.array().readonly(),\n});\n\n/**\n * Domain enum entry under `domain.namespaces[id].enum[name]`.\n * Carries the codec id and an ordered `members` array of `{name, value}` pairs.\n */\nexport const ContractEnumSchema = type({\n '+': 'reject',\n codecId: 'string',\n members: type({\n name: 'string',\n value: 'string',\n })\n .array()\n .readonly(),\n});\n\nconst PrimaryKeySchema = type.declare<PrimaryKeyInput>().type({\n columns: type.string.array().readonly(),\n 'name?': 'string',\n});\n\nconst UniqueConstraintSchema = type.declare<UniqueConstraintInput>().type({\n columns: type.string.array().readonly(),\n 'name?': 'string',\n});\n\nexport const IndexSchema = type({\n columns: type.string.array().readonly(),\n 'name?': 'string',\n 'type?': 'string',\n 'options?': 'Record<string, unknown>',\n});\n\nexport const ForeignKeyReferenceSchema = type({\n '+': 'reject',\n namespaceId: 'string',\n tableName: 'string',\n columns: type.string.array().readonly(),\n 'spaceId?': 'string',\n}) satisfies Type<ForeignKeyReferenceInput>;\n\nexport const ForeignKeySourceSchema = type({\n '+': 'reject',\n namespaceId: 'string',\n tableName: 'string',\n columns: type.string.array().readonly(),\n}) satisfies Type<ForeignKeyReferenceInput>;\n\nexport const ReferentialActionSchema = type\n .declare<ReferentialAction>()\n .type(\"'noAction' | 'restrict' | 'cascade' | 'setNull' | 'setDefault'\");\n\nexport const ForeignKeySchema = type.declare<ForeignKeyInput>().type({\n source: ForeignKeySourceSchema,\n target: ForeignKeyReferenceSchema,\n 'name?': 'string',\n 'onDelete?': ReferentialActionSchema,\n 'onUpdate?': ReferentialActionSchema,\n constraint: 'boolean',\n index: 'boolean',\n});\n\nexport const CheckConstraintSchema = type({\n '+': 'reject',\n name: 'string',\n column: 'string',\n valueSet: ValueSetRefSchema,\n});\n\nconst StorageTableSchema = type({\n '+': 'reject',\n columns: type({ '[string]': StorageColumnSchema }),\n 'primaryKey?': PrimaryKeySchema,\n uniques: UniqueConstraintSchema.array().readonly(),\n indexes: IndexSchema.array().readonly(),\n foreignKeys: ForeignKeySchema.array().readonly(),\n 'control?': ControlPolicySchema,\n 'checks?': CheckConstraintSchema.array().readonly(),\n});\n\n/**\n * Re-exported so target packs can register their `validatorSchema`\n * fragment without re-declaring the schema for the kinds the family\n * core already validates. Full extraction of enum-specific schemas\n * into the Postgres pack is a follow-up; today the symbol lives here.\n */\nexport { PostgresEnumTypeSchema };\n\n/**\n * Composes a hardcoded family `fallback` schema with optional\n * pack-contributed `fragments` keyed by the entry's `kind`\n * discriminator. The composition is **additive**, not substitutive:\n *\n * - No fragments registered → entries are validated by `fallback`\n * alone (the unchanged baseline).\n * - An entry's `kind` matches `fallbackKind` AND a fragment for that\n * kind is registered → the entry must pass **both** `fallback` and\n * the fragment. This preserves family-owned invariants (e.g. the\n * built-in `PostgresEnumType` shape) even when a pack contributes\n * its own schema for the same kind.\n * - An entry's `kind` matches a registered fragment for some\n * non-fallback kind → the fragment alone validates the entry.\n * `fallback` is family-specific (validates a single hardcoded kind)\n * and would reject any other kind, so it does not apply here.\n * - An entry's `kind` matches no fragment → fall through to\n * `fallback`.\n */\nfunction namespaceSlotEntrySchema(\n fallback: Type<unknown>,\n fallbackKind: string,\n fragments?: ReadonlyMap<string, Type<unknown>>,\n): Type<unknown> {\n if (fragments === undefined || fragments.size === 0) {\n return fallback;\n }\n return type('unknown').narrow((entry, ctx) => {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {\n return ctx.mustBe('an object');\n }\n const kind = (entry as { kind?: unknown }).kind;\n if (typeof kind === 'string') {\n const fragment = fragments.get(kind);\n if (fragment !== undefined) {\n if (kind === fallbackKind) {\n const baseParsed = fallback(entry);\n if (baseParsed instanceof type.errors) {\n return ctx.reject({ expected: baseParsed.summary });\n }\n }\n const parsed = fragment(entry);\n if (parsed instanceof type.errors) {\n return ctx.reject({ expected: parsed.summary });\n }\n return true;\n }\n }\n const parsed = fallback(entry);\n if (parsed instanceof type.errors) {\n return ctx.reject({ expected: parsed.summary });\n }\n return true;\n });\n}\n\n/**\n * Builds the per-namespace entry schema for `storage.namespaces[id]`.\n * Pack-contributed `validatorSchema` fragments — keyed by the\n * descriptor's `discriminator` — validate each entry by matching the\n * entry's `kind` field on the `'entries.type'` slot.\n */\nexport function createNamespaceEntrySchema(\n fragments?: ReadonlyMap<string, Type<unknown>>,\n): Type<unknown> {\n return type({\n '+': 'reject',\n id: 'string',\n 'kind?': 'string',\n entries: type({\n '+': 'reject',\n 'table?': type({ '[string]': StorageTableSchema }),\n 'type?': type({\n '[string]': namespaceSlotEntrySchema(PostgresEnumTypeSchema, 'postgres-enum', fragments),\n }),\n 'valueSet?': type({ '[string]': StorageValueSetSchema }),\n }),\n }) as Type<unknown>;\n}\n\n/**\n * Builds the storage schema. Pack contributions reach the per-namespace\n * entry shape through {@link createNamespaceEntrySchema}; the\n * document-scoped `storage.types` slot (codec triples only) and the\n * storage hash stay family-shared.\n */\nexport function createSqlStorageSchema(\n fragments?: ReadonlyMap<string, Type<unknown>>,\n): Type<unknown> {\n const namespaceEntry = createNamespaceEntrySchema(fragments);\n return type({\n '+': 'reject',\n storageHash: 'string',\n 'types?': type({ '[string]': DocumentScopedStorageTypeSchema }),\n // `__unbound__` is NOT required here: cross-namespace contracts can\n // declare only named namespaces (see cross-namespace FK fixtures). The\n // `__unbound__` brand on `SqlStorageInput['namespaces']` is kept sound at\n // construction time by injecting the unbound singleton when absent\n // (see `validateStorage` / `hydrateSqlStorage`), not by structural require.\n 'namespaces?': type({ '[string]': namespaceEntry }),\n }) as Type<unknown>;\n}\n\nconst StorageSchema = createSqlStorageSchema();\n\n// SQL-specific namespace walk shape (`entries.table` is the SQL family's\n// idiom). The wider `object` table value keeps this helper structurally\n// compatible with `SqlNamespace` and JSON envelope variants that lose class\n// identity.\ntype NamespacedStorageWalk = {\n readonly namespaces: Readonly<\n Record<\n string,\n Namespace & { readonly entries: { readonly table: Readonly<Record<string, object>> } }\n >\n >;\n};\n\nfunction eachStorageTable(storage: NamespacedStorageWalk) {\n return Object.entries(storage.namespaces).flatMap(([namespaceId, ns]) =>\n Object.entries(ns.entries.table).map(([tableName, table]) => ({\n namespaceId,\n tableName,\n table,\n })),\n );\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction findDuplicateValue(values: readonly string[]): string | undefined {\n const seen = new Set<string>();\n for (const value of values) {\n if (seen.has(value)) {\n return value;\n }\n seen.add(value);\n }\n return undefined;\n}\n\nfunction isContractFieldType(value: unknown): boolean {\n if (!isPlainRecord(value)) return false;\n const kind = value['kind'];\n if (kind === 'scalar') {\n if (typeof value['codecId'] !== 'string') return false;\n const typeParams = value['typeParams'];\n if (typeParams !== undefined && !isPlainRecord(typeParams)) return false;\n return true;\n }\n if (kind === 'valueObject') {\n return typeof value['name'] === 'string';\n }\n if (kind === 'union') {\n const members = value['members'];\n if (!Array.isArray(members)) return false;\n return members.every((m) => isContractFieldType(m));\n }\n return false;\n}\n\nconst ContractFieldTypeSchema = type('unknown').narrow((value, ctx) =>\n isContractFieldType(value) ? true : ctx.mustBe('scalar, valueObject, or union field type'),\n);\n\nconst ModelFieldSchema = type({\n '+': 'reject',\n nullable: 'boolean',\n type: ContractFieldTypeSchema,\n 'many?': 'true',\n 'dict?': 'true',\n 'valueSet?': ValueSetRefSchema,\n});\n\nconst ModelStorageFieldSchema = type({\n column: 'string',\n 'codecId?': 'string',\n 'nullable?': 'boolean',\n});\n\nconst ModelStorageSchema = type({\n table: 'string',\n namespaceId: 'string',\n fields: type({ '[string]': ModelStorageFieldSchema }),\n});\n\nconst ContractRelationThroughSchema = type({\n '+': 'reject',\n table: 'string',\n namespaceId: 'string',\n parentColumns: type.string.array().readonly(),\n childColumns: type.string.array().readonly(),\n targetColumns: type.string.array().readonly(),\n});\n\nconst ContractRelationOnSchema = type({\n '+': 'reject',\n localFields: type.string.array().readonly(),\n targetFields: type.string.array().readonly(),\n});\n\nconst ContractManyToManyRelationSchema = type({\n '+': 'reject',\n to: CrossReferenceSchema,\n cardinality: \"'N:M'\",\n on: ContractRelationOnSchema,\n through: ContractRelationThroughSchema,\n});\n\nconst ContractNonJunctionRelationSchema = type({\n '+': 'reject',\n to: CrossReferenceSchema,\n cardinality: \"'1:1' | '1:N' | 'N:1'\",\n on: ContractRelationOnSchema,\n});\n\nconst ContractReferenceRelationSchema = ContractManyToManyRelationSchema.or(\n ContractNonJunctionRelationSchema,\n);\n\nconst ContractEmbedRelationSchema = type({\n '+': 'reject',\n to: CrossReferenceSchema,\n cardinality: \"'1:1' | '1:N'\",\n});\n\nconst ContractRelationSchema = ContractReferenceRelationSchema.or(ContractEmbedRelationSchema);\n\nconst ModelSchema = type({\n storage: ModelStorageSchema,\n 'fields?': type({ '[string]': ModelFieldSchema }),\n 'relations?': type({ '[string]': ContractRelationSchema }),\n 'discriminator?': 'unknown',\n 'variants?': 'unknown',\n 'base?': CrossReferenceSchema,\n 'owner?': 'string',\n});\n\nconst ContractMetaSchema = type({\n '[string]': 'unknown',\n});\n\n/**\n * Builds the full SQL contract schema. The storage subtree threads\n * pack contributions through {@link createSqlStorageSchema}; the rest\n * of the contract envelope is family-shared.\n */\nexport function createSqlContractSchema(\n fragments?: ReadonlyMap<string, Type<unknown>>,\n): Type<unknown> {\n const storage = createSqlStorageSchema(fragments);\n return type({\n '+': 'reject',\n target: 'string',\n targetFamily: \"'sql'\",\n 'coreHash?': 'string',\n profileHash: 'string',\n 'capabilities?': 'Record<string, Record<string, boolean>>',\n 'extensionPacks?': 'Record<string, unknown>',\n 'meta?': ContractMetaSchema,\n 'defaultControlPolicy?': ControlPolicySchema,\n 'roots?': type({ '[string]': CrossReferenceSchema }),\n domain: type({\n namespaces: type({\n '[string]': type({\n models: type({ '[string]': ModelSchema }),\n 'valueObjects?': 'Record<string, unknown>',\n 'enum?': type({ '[string]': ContractEnumSchema }),\n }),\n }),\n }),\n storage,\n 'execution?': ExecutionSchema,\n }) as Type<unknown>;\n}\n\nconst SqlContractSchema = createSqlContractSchema();\n\n// NOTE: StorageColumnSchema, StorageTableSchema, and StorageSchema use bare type()\n// instead of type.declare<T>().type() because the ColumnDefault union's value field\n// includes bigint | Date (runtime-only types after decoding) which cannot be expressed\n// in Arktype's JSON validation DSL. The `as SqlStorage` cast in validateStorage() bridges\n// the gap between the JSON-safe Arktype output and the runtime TypeScript type.\n\n/**\n * Validates the structural shape of SqlStorage using Arktype.\n *\n * @param value - The storage value to validate\n * @returns The validated storage if structure is valid\n * @throws Error if the storage structure is invalid\n */\nexport function validateStorage(value: unknown): SqlStorage {\n const result = StorageSchema(value);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Storage validation failed: ${messages}`);\n }\n // Arktype validates the JSON-safe envelope, but the `ColumnDefault`\n // union carries runtime-only `bigint | Date` that the validation DSL\n // can't express (see NOTE above), so bridge the validated shape to the\n // input type. Construction below re-materialises nested IR fields.\n const validated = blindCast<\n SqlStorageInput & { readonly namespaces?: SqlStorageInput['namespaces'] },\n 'arktype validated the JSON envelope but its output type is unknown (ColumnDefault carries runtime-only bigint|Date); bridge to the input shape'\n >(result);\n const namespaces = buildSqlNamespaceMap(validated.namespaces ?? {});\n // Compatibility shim: inject the empty unbound singleton when absent so that\n // production code paths which address __unbound__ for table metadata have a\n // slot to read or write into. The `SqlStorageInput['namespaces']` type no\n // longer requires __unbound__, so this is a runtime convenience, not a type\n // invariant.\n const unbound = namespaces[UNBOUND_NAMESPACE_ID] ?? SqlUnboundNamespace.instance;\n return new SqlStorage({\n storageHash: validated.storageHash,\n ...ifDefined('types', validated.types),\n namespaces: { ...namespaces, [UNBOUND_NAMESPACE_ID]: unbound },\n });\n}\n\nexport function validateModel(value: unknown): unknown {\n const result = ModelSchema(value);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Model validation failed: ${messages}`);\n }\n return result;\n}\n\n/**\n * Structural arktype validation of an SQL contract envelope. Internal\n * helper for {@link validateSqlContractFully} — exposed only inside\n * this module, since the family seam-of-record is the\n * `SqlContractSerializerBase.deserializeContract` SPI.\n */\nfunction validateSqlContractStructure<T extends Contract<SqlStorage>>(\n value: unknown,\n contractSchema: Type<unknown>,\n): T {\n if (typeof value !== 'object' || value === null) {\n throw new ContractValidationError(\n 'Contract structural validation failed: value must be an object',\n 'structural',\n );\n }\n\n const rawValue = value as { targetFamily?: string };\n if (rawValue.targetFamily !== undefined && rawValue.targetFamily !== 'sql') {\n throw new ContractValidationError(\n `Unsupported target family: ${rawValue.targetFamily}`,\n 'structural',\n );\n }\n\n const contractResult = contractSchema(value);\n\n if (contractResult instanceof type.errors) {\n const messages = contractResult.map((p: { message: string }) => p.message).join('; ');\n throw new ContractValidationError(\n `Contract structural validation failed: ${messages}`,\n 'structural',\n );\n }\n\n // Arktype's inferred output type differs from T due to exactOptionalPropertyTypes\n // and branded hash types — the runtime value is structurally compatible after validation\n return contractResult as unknown as T;\n}\n\n/**\n * Validates semantic constraints on SqlStorage that cannot be expressed in Arktype schemas.\n *\n * Returns an array of human-readable error strings. Empty array = valid.\n *\n * Currently checks:\n * - duplicate named primary key / unique / index / foreign key objects within a table\n * - duplicate unique, index, or foreign key declarations within a table\n * - duplicate columns within primary key / unique / index definitions\n * - nullable columns in primary key definitions\n * - `setNull` referential action on a non-nullable FK column (would fail at runtime)\n * - `setDefault` referential action on a non-nullable FK column without a DEFAULT (would fail at runtime)\n */\nexport function validateStorageSemantics(storage: SqlStorage): string[] {\n const errors: string[] = [];\n\n for (const { namespaceId, tableName, table: rawTable } of eachStorageTable(storage)) {\n const table = rawTable as StorageTable;\n const namedObjects = new Map<string, string[]>();\n const registerNamedObject = (kind: string, name: string | undefined) => {\n if (!name) return;\n namedObjects.set(name, [...(namedObjects.get(name) ?? []), kind]);\n };\n\n registerNamedObject('primary key', table.primaryKey?.name);\n for (const unique of table.uniques) {\n registerNamedObject('unique constraint', unique.name);\n }\n for (const index of table.indexes) {\n registerNamedObject('index', index.name);\n }\n for (const fk of table.foreignKeys) {\n registerNamedObject('foreign key', fk.name);\n }\n for (const check of table.checks ?? []) {\n registerNamedObject('check constraint', check.name);\n }\n\n for (const [name, kinds] of namedObjects) {\n if (kinds.length > 1) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": named object \"${name}\" is declared multiple times (${kinds.join(', ')})`,\n );\n }\n }\n\n if (table.primaryKey) {\n const duplicateColumn = findDuplicateValue(table.primaryKey.columns);\n if (duplicateColumn !== undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": primary key contains duplicate column \"${duplicateColumn}\"`,\n );\n }\n\n for (const columnName of table.primaryKey.columns) {\n const column = table.columns[columnName];\n if (column?.nullable === true) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": primary key column \"${columnName}\" is nullable; primary key columns must be NOT NULL`,\n );\n }\n }\n }\n\n const seenUniqueDefinitions = new Set<string>();\n for (const unique of table.uniques) {\n const duplicateColumn = findDuplicateValue(unique.columns);\n if (duplicateColumn !== undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": unique constraint contains duplicate column \"${duplicateColumn}\"`,\n );\n }\n\n const signature = JSON.stringify({ columns: unique.columns });\n if (seenUniqueDefinitions.has(signature)) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": duplicate unique constraint definition on columns [${unique.columns.join(', ')}]`,\n );\n continue;\n }\n seenUniqueDefinitions.add(signature);\n }\n\n const sortOptions = (o: Record<string, unknown> | undefined): Record<string, unknown> | null =>\n o ? Object.fromEntries(Object.entries(o).sort(([a], [b]) => a.localeCompare(b))) : null;\n\n const seenIndexDefinitions = new Set<string>();\n for (const index of table.indexes) {\n const duplicateColumn = findDuplicateValue(index.columns);\n if (duplicateColumn !== undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": index contains duplicate column \"${duplicateColumn}\"`,\n );\n }\n\n const signature = JSON.stringify({\n columns: index.columns,\n type: index.type ?? null,\n options: sortOptions(index.options),\n });\n if (seenIndexDefinitions.has(signature)) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": duplicate index definition on columns [${index.columns.join(', ')}]`,\n );\n continue;\n }\n seenIndexDefinitions.add(signature);\n }\n\n const seenForeignKeyDefinitions = new Set<string>();\n for (const fk of table.foreignKeys) {\n const signature = JSON.stringify({\n source: fk.source,\n target: fk.target,\n onDelete: fk.onDelete ?? null,\n onUpdate: fk.onUpdate ?? null,\n constraint: fk.constraint,\n index: fk.index,\n });\n if (seenForeignKeyDefinitions.has(signature)) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": duplicate foreign key definition on columns [${fk.source.columns.join(', ')}]`,\n );\n continue;\n }\n seenForeignKeyDefinitions.add(signature);\n }\n\n for (const fk of table.foreignKeys) {\n for (const colName of fk.source.columns) {\n const column = table.columns[colName];\n if (!column) continue;\n\n if (fk.onDelete === 'setNull' && !column.nullable) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": onDelete setNull on foreign key column \"${colName}\" which is NOT NULL`,\n );\n }\n if (fk.onUpdate === 'setNull' && !column.nullable) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": onUpdate setNull on foreign key column \"${colName}\" which is NOT NULL`,\n );\n }\n if (fk.onDelete === 'setDefault' && !column.nullable && column.default === undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": onDelete setDefault on foreign key column \"${colName}\" which is NOT NULL and has no DEFAULT`,\n );\n }\n if (fk.onUpdate === 'setDefault' && !column.nullable && column.default === undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": onUpdate setDefault on foreign key column \"${colName}\" which is NOT NULL and has no DEFAULT`,\n );\n }\n }\n }\n\n const seenCheckDefinitions = new Set<string>();\n for (const check of table.checks ?? []) {\n const signature = JSON.stringify({ column: check.column, valueSet: check.valueSet });\n if (seenCheckDefinitions.has(signature)) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": duplicate check constraint definition on column \"${check.column}\"`,\n );\n continue;\n }\n seenCheckDefinitions.add(signature);\n }\n }\n\n return errors;\n}\n\n/**\n * SQL storage logical-consistency checks: every model.storage.table\n * resolves to a real table, every model.storage.fields[*].column\n * resolves to a real column, and value-object fields land on JSON-native\n * columns. Throws `ContractValidationError` on the first mismatch.\n */\nexport function validateModelStorageReferences(contract: Contract<SqlStorage>): void {\n for (const [namespaceId, namespace] of Object.entries(contract.domain.namespaces)) {\n const models = namespace.models as Record<string, ContractModel<SqlModelStorage>>;\n for (const [modelName, model] of Object.entries(models)) {\n const qualifiedName = `${namespaceId}:${modelName}`;\n const storageNamespaceId = model.storage.namespaceId;\n if (storageNamespaceId !== namespaceId) {\n throw new ContractValidationError(\n `Model \"${qualifiedName}\" storage.namespaceId \"${storageNamespaceId}\" does not match domain namespace \"${namespaceId}\"`,\n 'storage',\n );\n }\n\n const storageTable = model.storage.table;\n const rawTable = contract.storage.namespaces[storageNamespaceId]?.entries.table[storageTable];\n if (rawTable === undefined) {\n throw new ContractValidationError(\n `Model \"${qualifiedName}\" references non-existent table \"${storageNamespaceId}.${storageTable}\"`,\n 'storage',\n );\n }\n\n const table = rawTable as StorageTable;\n\n const columnNames = new Set(Object.keys(table.columns));\n for (const [fieldName, field] of Object.entries(model.storage.fields)) {\n if (!columnNames.has(field.column)) {\n throw new ContractValidationError(\n `Model \"${qualifiedName}\" field \"${fieldName}\" references non-existent column \"${field.column}\" in table \"${storageTable}\"`,\n 'storage',\n );\n }\n }\n\n const JSON_NATIVE_TYPES = new Set(['json', 'jsonb']);\n for (const [fieldName, domainField] of Object.entries(model.fields ?? {})) {\n const f = domainField as ContractField;\n if (f.type?.kind !== 'valueObject') continue;\n const storageField = model.storage.fields[fieldName];\n if (!storageField) continue;\n const column = table.columns[storageField.column];\n if (!column) continue;\n if (!JSON_NATIVE_TYPES.has(column.nativeType)) {\n throw new ContractValidationError(\n `Model \"${qualifiedName}\" field \"${fieldName}\" is a value object but storage column \"${storageField.column}\" has nativeType \"${column.nativeType}\" (expected json or jsonb)`,\n 'storage',\n );\n }\n }\n }\n }\n}\n\n/**\n * Cross-table consistency checks for SQL storage: primary key, unique,\n * index, and foreign key column references resolve to real columns;\n * NOT NULL columns don't carry a literal `null` default; FK column\n * counts match their referenced columns. Throws on the first mismatch.\n */\nexport function validateSqlStorageConsistency(contract: Contract<SqlStorage>): void {\n for (const { namespaceId, tableName, table: rawTable } of eachStorageTable(contract.storage)) {\n const table = rawTable as StorageTable;\n const columnNames = new Set(Object.keys(table.columns));\n\n if (table.primaryKey) {\n for (const colName of table.primaryKey.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" primaryKey references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n }\n\n for (const unique of table.uniques) {\n for (const colName of unique.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" unique constraint references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n }\n\n for (const index of table.indexes) {\n for (const colName of index.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" index references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n }\n\n for (const check of table.checks ?? []) {\n if (!columnNames.has(check.column)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" check constraint \"${check.name}\" references non-existent column \"${check.column}\"`,\n 'storage',\n );\n }\n }\n\n for (const [colName, column] of Object.entries(table.columns)) {\n if (!column.nullable && column.default?.kind === 'literal' && column.default.value === null) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" column \"${colName}\" is NOT NULL but has a literal null default`,\n 'storage',\n );\n }\n }\n\n for (const fk of table.foreignKeys) {\n if (fk.source.namespaceId !== namespaceId || fk.source.tableName !== tableName) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" contains foreignKey with mismatched source coordinates (${fk.source.namespaceId}.${fk.source.tableName})`,\n 'storage',\n );\n }\n\n for (const colName of fk.source.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" foreignKey references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n\n if (fk.target.spaceId === undefined) {\n const targetNamespace = contract.storage.namespaces[fk.target.namespaceId];\n const referencedRaw = targetNamespace?.entries.table[fk.target.tableName];\n if (referencedRaw === undefined) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" foreignKey references non-existent table \"${fk.target.namespaceId}.${fk.target.tableName}\"`,\n 'storage',\n );\n }\n const referencedTable = referencedRaw as StorageTable;\n const referencedColumnNames = new Set(Object.keys(referencedTable.columns));\n for (const colName of fk.target.columns) {\n if (!referencedColumnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" foreignKey references non-existent column \"${colName}\" in table \"${fk.target.tableName}\"`,\n 'storage',\n );\n }\n }\n }\n\n if (fk.source.columns.length !== fk.target.columns.length) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" foreignKey column count (${fk.source.columns.length}) does not match referenced column count (${fk.target.columns.length})`,\n 'storage',\n );\n }\n }\n }\n}\n\nexport interface ValidateSqlContractFullyOptions {\n /**\n * Precomputed structural schema to validate against. Built once at\n * serializer construction time when the family `ContractSerializer`\n * has folded pack-contributed `validatorSchema` fragments into the\n * per-namespace entry shape; absent for the family-default validator\n * path (no pack contributions). Falls back to the cached default\n * `SqlContractSchema` when omitted.\n */\n readonly contractSchema?: Type<unknown>;\n}\n\n/**\n * Full SQL contract validation: structural (arktype) +\n * framework-shared domain + SQL storage logical-consistency + SQL\n * storage semantic + model ↔ storage reference checks. Throws\n * `ContractValidationError` on the first failure. Returns the\n * validated flat-data shape; IR class hydration happens in the SPI\n * base on top of this helper.\n */\nexport function validateSqlContractFully<T extends Contract<SqlStorage>>(\n value: unknown,\n options?: ValidateSqlContractFullyOptions,\n): T {\n const stripped =\n typeof value === 'object' && value !== null\n ? (() => {\n const { schemaVersion: _, _generated: _g, ...rest } = value as Record<string, unknown>;\n return rest;\n })()\n : value;\n const schema = options?.contractSchema ?? SqlContractSchema;\n const validated = validateSqlContractStructure<T>(stripped, schema);\n validateContractDomain({\n roots: validated.roots,\n domain: validated.domain,\n });\n validateSqlStorageConsistency(validated);\n const semanticErrors = validateStorageSemantics(validated.storage);\n if (semanticErrors.length > 0) {\n throw new ContractValidationError(\n `Contract semantic validation failed: ${semanticErrors.join('; ')}`,\n 'storage',\n );\n }\n validateModelStorageReferences(validated);\n return validated;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validators.mjs","names":["f","referencedTable"],"sources":["../src/validators.ts"],"sourcesContent":["import { ContractValidationError } from '@prisma-next/contract/contract-validation-error';\nimport {\n type Contract,\n type ContractField,\n type ContractModel,\n CrossReferenceSchema,\n} from '@prisma-next/contract/types';\nimport { validateContractDomain } from '@prisma-next/contract/validate-domain';\nimport { type Namespace, UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport { blindCast, castAs } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { type Type, type } from 'arktype';\nimport { buildSqlNamespaceMap } from './ir/build-sql-namespace';\nimport { SqlUnboundNamespace } from './ir/sql-unbound-namespace';\nimport {\n type ForeignKeyInput,\n type ForeignKeyReferenceInput,\n type PrimaryKeyInput,\n type ReferentialAction,\n type SqlModelStorage,\n SqlStorage,\n type SqlStorageInput,\n type StorageTable,\n type StorageTypeInstanceInput,\n type UniqueConstraintInput,\n} from './types';\n\ntype ColumnDefaultLiteral = {\n readonly kind: 'literal';\n readonly value: string | number | boolean | Record<string, unknown> | unknown[] | null;\n};\ntype ColumnDefaultFunction = { readonly kind: 'function'; readonly expression: string };\nconst literalKindSchema = type(\"'literal'\");\nconst functionKindSchema = type(\"'function'\");\nconst generatorKindSchema = type(\"'generator'\");\nconst ControlPolicySchema = type(\"'managed' | 'tolerated' | 'external' | 'observed'\");\nconst generatorIdSchema = type('string').narrow((value, ctx) => {\n return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value) ? true : ctx.mustBe('a flat generator id');\n});\n\nexport const ColumnDefaultLiteralSchema = type.declare<ColumnDefaultLiteral>().type({\n kind: literalKindSchema,\n value: 'string | number | boolean | null | unknown[] | Record<string, unknown>',\n});\n\nexport const ColumnDefaultFunctionSchema = type.declare<ColumnDefaultFunction>().type({\n kind: functionKindSchema,\n expression: 'string',\n});\n\nexport const ColumnDefaultSchema = ColumnDefaultLiteralSchema.or(ColumnDefaultFunctionSchema);\n\nconst ExecutionMutationDefaultValueSchema = type({\n '+': 'reject',\n kind: generatorKindSchema,\n id: generatorIdSchema,\n 'params?': 'Record<string, unknown>',\n});\n\nconst ExecutionMutationDefaultSchema = type({\n '+': 'reject',\n ref: {\n '+': 'reject',\n table: 'string',\n column: 'string',\n },\n 'onCreate?': ExecutionMutationDefaultValueSchema,\n 'onUpdate?': ExecutionMutationDefaultValueSchema,\n});\n\nconst ExecutionSchema = type({\n '+': 'reject',\n executionHash: 'string',\n mutations: {\n '+': 'reject',\n defaults: ExecutionMutationDefaultSchema.array().readonly(),\n },\n});\n\nconst StorageValueSetRefSchema = type({\n plane: \"'storage'\",\n namespaceId: 'string',\n entityKind: \"'valueSet'\",\n entityName: 'string',\n 'spaceId?': 'string',\n});\n\nconst DomainEnumRefSchema = type({\n plane: \"'domain'\",\n namespaceId: 'string',\n entityKind: \"'enum'\",\n entityName: 'string',\n 'spaceId?': 'string',\n});\n\nconst StorageColumnSchema = type({\n '+': 'reject',\n nativeType: 'string',\n codecId: 'string',\n nullable: 'boolean',\n 'typeParams?': 'Record<string, unknown>',\n 'typeRef?': 'string',\n 'default?': ColumnDefaultSchema,\n 'control?': ControlPolicySchema,\n 'valueSet?': StorageValueSetRefSchema,\n}).narrow((col, ctx) => {\n if (col.typeParams !== undefined && col.typeRef !== undefined) {\n return ctx.mustBe('a column with either typeParams or typeRef, not both');\n }\n return true;\n});\n\n/**\n * Codec-triple entry persisted under `storage.types[name]`. Carries an\n * enumerable literal `kind: 'codec-instance'` discriminator so the\n * polymorphic slot dispatch can distinguish codec triples.\n */\nconst StorageTypeInstanceSchema = type\n .declare<StorageTypeInstanceInput & { kind: 'codec-instance' }>()\n .type({\n kind: \"'codec-instance'\",\n codecId: 'string',\n nativeType: 'string',\n 'typeParams?': 'Record<string, unknown>',\n });\n\n/** Document-scoped `storage.types`: codec triples only. */\nconst DocumentScopedStorageTypeSchema = StorageTypeInstanceSchema;\n\n/**\n * Storage value-set entry under `storage.namespaces[id].entries.valueSet[name]`.\n * Carries a `kind: 'valueSet'` discriminator (enumerable, survives JSON) and an\n * ordered `values` array of codec-encoded permitted values.\n */\nexport const StorageValueSetSchema = type({\n kind: \"'valueSet'\",\n values: type('string | number | boolean | null | unknown[] | Record<string, unknown>')\n .array()\n .readonly(),\n});\n\n/**\n * Domain enum entry under `domain.namespaces[id].enum[name]`.\n * Carries the codec id and an ordered `members` array of `{name, value}` pairs.\n */\nexport const ContractEnumSchema = type({\n '+': 'reject',\n codecId: 'string',\n members: type({\n name: 'string',\n value: 'string | number | boolean | null | unknown[] | Record<string, unknown>',\n })\n .array()\n .readonly(),\n});\n\nconst PrimaryKeySchema = type.declare<PrimaryKeyInput>().type({\n columns: type.string.array().readonly(),\n 'name?': 'string',\n});\n\nconst UniqueConstraintSchema = type.declare<UniqueConstraintInput>().type({\n columns: type.string.array().readonly(),\n 'name?': 'string',\n});\n\nexport const IndexSchema = type({\n columns: type.string.array().readonly(),\n 'name?': 'string',\n 'type?': 'string',\n 'options?': 'Record<string, unknown>',\n});\n\nexport const ForeignKeyReferenceSchema = type({\n '+': 'reject',\n namespaceId: 'string',\n tableName: 'string',\n columns: type.string.array().readonly(),\n 'spaceId?': 'string',\n}) satisfies Type<ForeignKeyReferenceInput>;\n\nexport const ForeignKeySourceSchema = type({\n '+': 'reject',\n namespaceId: 'string',\n tableName: 'string',\n columns: type.string.array().readonly(),\n}) satisfies Type<ForeignKeyReferenceInput>;\n\nexport const ReferentialActionSchema = type\n .declare<ReferentialAction>()\n .type(\"'noAction' | 'restrict' | 'cascade' | 'setNull' | 'setDefault'\");\n\nexport const ForeignKeySchema = type.declare<ForeignKeyInput>().type({\n source: ForeignKeySourceSchema,\n target: ForeignKeyReferenceSchema,\n 'name?': 'string',\n 'onDelete?': ReferentialActionSchema,\n 'onUpdate?': ReferentialActionSchema,\n constraint: 'boolean',\n index: 'boolean',\n});\n\nexport const CheckConstraintSchema = type({\n '+': 'reject',\n name: 'string',\n column: 'string',\n valueSet: StorageValueSetRefSchema,\n});\n\nconst StorageTableSchema = type({\n '+': 'reject',\n columns: type({ '[string]': StorageColumnSchema }),\n 'primaryKey?': PrimaryKeySchema,\n uniques: UniqueConstraintSchema.array().readonly(),\n indexes: IndexSchema.array().readonly(),\n foreignKeys: ForeignKeySchema.array().readonly(),\n 'control?': ControlPolicySchema,\n 'checks?': CheckConstraintSchema.array().readonly(),\n});\n\n/**\n * Composes the single entry-validator registry consulted during\n * structural validation. SQL core registers its own kinds (`'table'`,\n * `'valueSet'`) into the same registry targets extend — there is no\n * separate built-in fallback tier. Target packs pass their contributed\n * kinds via `packSchemas`.\n */\nexport function createSqlEntrySchemaRegistry(\n packSchemas?: ReadonlyMap<string, Type<unknown>>,\n): ReadonlyMap<string, Type<unknown>> {\n const registry = new Map<string, Type<unknown>>([\n ['table', castAs<Type<unknown>>(StorageTableSchema)],\n ['valueSet', castAs<Type<unknown>>(StorageValueSetSchema)],\n ]);\n if (packSchemas !== undefined) {\n for (const [kind, schema] of packSchemas) {\n if (registry.has(kind)) {\n throw new Error(\n `createSqlEntrySchemaRegistry: pack schema \"${kind}\" collides with a core kind — pack schemas cannot override \"table\" or \"valueSet\"`,\n );\n }\n registry.set(kind, schema);\n }\n }\n return registry;\n}\n\n/**\n * Builds the per-namespace entry schema for `storage.namespaces[id]`.\n *\n * Validation is registry-driven: the `registry` parameter maps each\n * entries key to an arktype schema that validates a single inner-map\n * value for that kind. Compose the registry with\n * {@link createSqlEntrySchemaRegistry} — SQL core's kinds and pack\n * contributions live in the same map. An unregistered key fails\n * validation naming the kind and the namespace id, so validation fails\n * closed.\n */\nexport function createNamespaceEntrySchema(\n registry: ReadonlyMap<string, Type<unknown>>,\n): Type<unknown> {\n return type({\n '+': 'reject',\n id: 'string',\n 'kind?': 'string',\n entries: 'object',\n }).narrow((ns, ctx) => {\n if (!isPlainRecord(ns.entries)) {\n return ctx.mustBe('an entries object');\n }\n for (const [key, innerMap] of Object.entries(ns.entries)) {\n const entrySchema = registry.get(key);\n if (entrySchema === undefined) {\n return ctx.reject({\n expected: `entries key \"${key}\" in namespace \"${ns.id}\" is not a registered entity kind`,\n });\n }\n if (!isPlainRecord(innerMap)) {\n return ctx.reject({\n expected: `entries[\"${key}\"] in namespace \"${ns.id}\" must be an object`,\n });\n }\n for (const [, value] of Object.entries(innerMap)) {\n const parsed = entrySchema(value);\n if (parsed instanceof type.errors) {\n return ctx.reject({ expected: parsed.summary });\n }\n }\n }\n return true;\n }) as Type<unknown>;\n}\n\n/**\n * Builds the storage schema. Pack contributions reach the per-namespace\n * entry shape through {@link createNamespaceEntrySchema}; the\n * document-scoped `storage.types` field (codec triples only) and the\n * storage hash stay family-shared.\n */\nexport function createSqlStorageSchema(\n registry: ReadonlyMap<string, Type<unknown>>,\n): Type<unknown> {\n const namespaceEntry = createNamespaceEntrySchema(registry);\n return type({\n '+': 'reject',\n storageHash: 'string',\n 'types?': type({ '[string]': DocumentScopedStorageTypeSchema }),\n // `__unbound__` is NOT required here: cross-namespace contracts can\n // declare only named namespaces (see cross-namespace FK fixtures). The\n // `__unbound__` brand on `SqlStorageInput['namespaces']` is kept sound at\n // construction time by injecting the unbound singleton when absent\n // (see `validateStorage` / `hydrateSqlStorage`), not by structural require.\n 'namespaces?': type({ '[string]': namespaceEntry }),\n }) as Type<unknown>;\n}\n\nconst StorageSchema = createSqlStorageSchema(createSqlEntrySchemaRegistry());\n\ntype NamespacedStorageWalk = {\n readonly namespaces: Readonly<\n Record<\n string,\n Namespace & { readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>> }\n >\n >;\n};\n\nfunction eachStorageTable(storage: NamespacedStorageWalk) {\n return Object.entries(storage.namespaces).flatMap(([namespaceId, ns]) =>\n Object.entries(ns.entries['table'] ?? {}).map(([tableName, table]) => ({\n namespaceId,\n tableName,\n table,\n })),\n );\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value) as unknown;\n return proto === Object.prototype || proto === null;\n}\n\nfunction findDuplicateValue(values: readonly string[]): string | undefined {\n const seen = new Set<string>();\n for (const value of values) {\n if (seen.has(value)) {\n return value;\n }\n seen.add(value);\n }\n return undefined;\n}\n\nfunction isContractFieldType(value: unknown): boolean {\n if (!isPlainRecord(value)) return false;\n const kind = value['kind'];\n if (kind === 'scalar') {\n if (typeof value['codecId'] !== 'string') return false;\n const typeParams = value['typeParams'];\n if (typeParams !== undefined && !isPlainRecord(typeParams)) return false;\n return true;\n }\n if (kind === 'valueObject') {\n return typeof value['name'] === 'string';\n }\n if (kind === 'union') {\n const members = value['members'];\n if (!Array.isArray(members)) return false;\n return members.every((m) => isContractFieldType(m));\n }\n return false;\n}\n\nconst ContractFieldTypeSchema = type('unknown').narrow((value, ctx) =>\n isContractFieldType(value) ? true : ctx.mustBe('scalar, valueObject, or union field type'),\n);\n\nconst ModelFieldSchema = type({\n '+': 'reject',\n nullable: 'boolean',\n type: ContractFieldTypeSchema,\n 'many?': 'true',\n 'dict?': 'true',\n 'valueSet?': DomainEnumRefSchema,\n});\n\nconst ModelStorageFieldSchema = type({\n column: 'string',\n 'codecId?': 'string',\n 'nullable?': 'boolean',\n});\n\nconst ModelStorageSchema = type({\n table: 'string',\n namespaceId: 'string',\n fields: type({ '[string]': ModelStorageFieldSchema }),\n});\n\nconst ContractRelationThroughSchema = type({\n '+': 'reject',\n table: 'string',\n namespaceId: 'string',\n parentColumns: type.string.array().readonly(),\n childColumns: type.string.array().readonly(),\n targetColumns: type.string.array().readonly(),\n});\n\nconst ContractRelationOnSchema = type({\n '+': 'reject',\n localFields: type.string.array().readonly(),\n targetFields: type.string.array().readonly(),\n});\n\nconst ContractManyToManyRelationSchema = type({\n '+': 'reject',\n to: CrossReferenceSchema,\n cardinality: \"'N:M'\",\n on: ContractRelationOnSchema,\n through: ContractRelationThroughSchema,\n});\n\nconst ContractNonJunctionRelationSchema = type({\n '+': 'reject',\n to: CrossReferenceSchema,\n cardinality: \"'1:1' | '1:N' | 'N:1'\",\n on: ContractRelationOnSchema,\n});\n\nconst ContractReferenceRelationSchema = ContractManyToManyRelationSchema.or(\n ContractNonJunctionRelationSchema,\n);\n\nconst ContractEmbedRelationSchema = type({\n '+': 'reject',\n to: CrossReferenceSchema,\n cardinality: \"'1:1' | '1:N'\",\n});\n\nconst ContractRelationSchema = ContractReferenceRelationSchema.or(ContractEmbedRelationSchema);\n\nconst ModelSchema = type({\n storage: ModelStorageSchema,\n 'fields?': type({ '[string]': ModelFieldSchema }),\n 'relations?': type({ '[string]': ContractRelationSchema }),\n 'discriminator?': 'unknown',\n 'variants?': 'unknown',\n 'base?': CrossReferenceSchema,\n 'owner?': 'string',\n});\n\nconst ContractMetaSchema = type({\n '[string]': 'unknown',\n});\n\n/**\n * Builds the full SQL contract schema. The storage subtree threads\n * pack contributions through {@link createSqlStorageSchema}; the rest\n * of the contract envelope is family-shared.\n */\nexport function createSqlContractSchema(\n registry: ReadonlyMap<string, Type<unknown>>,\n): Type<unknown> {\n const storage = createSqlStorageSchema(registry);\n return type({\n '+': 'reject',\n target: 'string',\n targetFamily: \"'sql'\",\n 'coreHash?': 'string',\n profileHash: 'string',\n 'capabilities?': 'Record<string, Record<string, boolean>>',\n 'extensionPacks?': 'Record<string, unknown>',\n 'meta?': ContractMetaSchema,\n 'defaultControlPolicy?': ControlPolicySchema,\n 'roots?': type({ '[string]': CrossReferenceSchema }),\n domain: type({\n namespaces: type({\n '[string]': type({\n models: type({ '[string]': ModelSchema }),\n 'valueObjects?': 'Record<string, unknown>',\n 'enum?': type({ '[string]': ContractEnumSchema }),\n }),\n }),\n }),\n storage,\n 'execution?': ExecutionSchema,\n }) as Type<unknown>;\n}\n\nconst SqlContractSchema = createSqlContractSchema(createSqlEntrySchemaRegistry());\n\n// NOTE: StorageColumnSchema, StorageTableSchema, and StorageSchema use bare type()\n// instead of type.declare<T>().type() because the ColumnDefault union's value field\n// includes bigint | Date (runtime-only types after decoding) which cannot be expressed\n// in Arktype's JSON validation DSL. The `as SqlStorage` cast in validateStorage() bridges\n// the gap between the JSON-safe Arktype output and the runtime TypeScript type.\n\n/**\n * Validates the structural shape of SqlStorage using Arktype.\n *\n * @param value - The storage value to validate\n * @returns The validated storage if structure is valid\n * @throws Error if the storage structure is invalid\n */\nexport function validateStorage(value: unknown): SqlStorage {\n const result = StorageSchema(value);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Storage validation failed: ${messages}`);\n }\n // Arktype validates the JSON-safe envelope, but the `ColumnDefault`\n // union carries runtime-only `bigint | Date` that the validation DSL\n // can't express (see NOTE above), so bridge the validated shape to the\n // input type. Construction below re-materialises nested IR fields.\n const validated = blindCast<\n SqlStorageInput & { readonly namespaces?: SqlStorageInput['namespaces'] },\n 'arktype validated the JSON envelope but its output type is unknown (ColumnDefault carries runtime-only bigint|Date); bridge to the input shape'\n >(result);\n const namespaces = buildSqlNamespaceMap(validated.namespaces ?? {});\n // Compatibility shim: inject the empty unbound singleton when absent so that\n // production code paths which address __unbound__ for table metadata have a\n // slot to read or write into. The `SqlStorageInput['namespaces']` type no\n // longer requires __unbound__, so this is a runtime convenience, not a type\n // invariant.\n const unbound = namespaces[UNBOUND_NAMESPACE_ID] ?? SqlUnboundNamespace.instance;\n return new SqlStorage({\n storageHash: validated.storageHash,\n ...ifDefined('types', validated.types),\n namespaces: { ...namespaces, [UNBOUND_NAMESPACE_ID]: unbound },\n });\n}\n\nexport function validateModel(value: unknown): unknown {\n const result = ModelSchema(value);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Model validation failed: ${messages}`);\n }\n return result;\n}\n\n/**\n * Structural arktype validation of an SQL contract envelope. Internal\n * helper for {@link validateSqlContractFully} — exposed only inside\n * this module, since the family seam-of-record is the\n * `SqlContractSerializerBase.deserializeContract` SPI.\n */\nfunction validateSqlContractStructure<T extends Contract<SqlStorage>>(\n value: unknown,\n contractSchema: Type<unknown>,\n): T {\n if (typeof value !== 'object' || value === null) {\n throw new ContractValidationError(\n 'Contract structural validation failed: value must be an object',\n 'structural',\n );\n }\n\n const rawValue = value as { targetFamily?: string };\n if (rawValue.targetFamily !== undefined && rawValue.targetFamily !== 'sql') {\n throw new ContractValidationError(\n `Unsupported target family: ${rawValue.targetFamily}`,\n 'structural',\n );\n }\n\n const contractResult = contractSchema(value);\n\n if (contractResult instanceof type.errors) {\n const messages = contractResult.map((p: { message: string }) => p.message).join('; ');\n throw new ContractValidationError(\n `Contract structural validation failed: ${messages}`,\n 'structural',\n );\n }\n\n // Arktype's inferred output type differs from T due to exactOptionalPropertyTypes\n // and branded hash types — the runtime value is structurally compatible after validation\n return contractResult as unknown as T;\n}\n\n/**\n * Validates semantic constraints on SqlStorage that cannot be expressed in Arktype schemas.\n *\n * Returns an array of human-readable error strings. Empty array = valid.\n *\n * Currently checks:\n * - duplicate named primary key / unique / index / foreign key objects within a table\n * - duplicate unique, index, or foreign key declarations within a table\n * - duplicate columns within primary key / unique / index definitions\n * - nullable columns in primary key definitions\n * - `setNull` referential action on a non-nullable FK column (would fail at runtime)\n * - `setDefault` referential action on a non-nullable FK column without a DEFAULT (would fail at runtime)\n */\nexport function validateStorageSemantics(storage: SqlStorage): string[] {\n const errors: string[] = [];\n\n for (const { namespaceId, tableName, table: rawTable } of eachStorageTable(storage)) {\n const table = rawTable as StorageTable;\n const namedObjects = new Map<string, string[]>();\n const registerNamedObject = (kind: string, name: string | undefined) => {\n if (!name) return;\n namedObjects.set(name, [...(namedObjects.get(name) ?? []), kind]);\n };\n\n registerNamedObject('primary key', table.primaryKey?.name);\n for (const unique of table.uniques) {\n registerNamedObject('unique constraint', unique.name);\n }\n for (const index of table.indexes) {\n registerNamedObject('index', index.name);\n }\n for (const fk of table.foreignKeys) {\n registerNamedObject('foreign key', fk.name);\n }\n for (const check of table.checks ?? []) {\n registerNamedObject('check constraint', check.name);\n }\n\n for (const [name, kinds] of namedObjects) {\n if (kinds.length > 1) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": named object \"${name}\" is declared multiple times (${kinds.join(', ')})`,\n );\n }\n }\n\n if (table.primaryKey) {\n const duplicateColumn = findDuplicateValue(table.primaryKey.columns);\n if (duplicateColumn !== undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": primary key contains duplicate column \"${duplicateColumn}\"`,\n );\n }\n\n for (const columnName of table.primaryKey.columns) {\n const column = table.columns[columnName];\n if (column?.nullable === true) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": primary key column \"${columnName}\" is nullable; primary key columns must be NOT NULL`,\n );\n }\n }\n }\n\n const seenUniqueDefinitions = new Set<string>();\n for (const unique of table.uniques) {\n const duplicateColumn = findDuplicateValue(unique.columns);\n if (duplicateColumn !== undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": unique constraint contains duplicate column \"${duplicateColumn}\"`,\n );\n }\n\n const signature = JSON.stringify({ columns: unique.columns });\n if (seenUniqueDefinitions.has(signature)) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": duplicate unique constraint definition on columns [${unique.columns.join(', ')}]`,\n );\n continue;\n }\n seenUniqueDefinitions.add(signature);\n }\n\n const sortOptions = (o: Record<string, unknown> | undefined): Record<string, unknown> | null =>\n o ? Object.fromEntries(Object.entries(o).sort(([a], [b]) => a.localeCompare(b))) : null;\n\n const seenIndexDefinitions = new Set<string>();\n for (const index of table.indexes) {\n const duplicateColumn = findDuplicateValue(index.columns);\n if (duplicateColumn !== undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": index contains duplicate column \"${duplicateColumn}\"`,\n );\n }\n\n const signature = JSON.stringify({\n columns: index.columns,\n type: index.type ?? null,\n options: sortOptions(index.options),\n });\n if (seenIndexDefinitions.has(signature)) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": duplicate index definition on columns [${index.columns.join(', ')}]`,\n );\n continue;\n }\n seenIndexDefinitions.add(signature);\n }\n\n const seenForeignKeyDefinitions = new Set<string>();\n for (const fk of table.foreignKeys) {\n const signature = JSON.stringify({\n source: fk.source,\n target: fk.target,\n onDelete: fk.onDelete ?? null,\n onUpdate: fk.onUpdate ?? null,\n constraint: fk.constraint,\n index: fk.index,\n });\n if (seenForeignKeyDefinitions.has(signature)) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": duplicate foreign key definition on columns [${fk.source.columns.join(', ')}]`,\n );\n continue;\n }\n seenForeignKeyDefinitions.add(signature);\n }\n\n for (const fk of table.foreignKeys) {\n for (const colName of fk.source.columns) {\n const column = table.columns[colName];\n if (!column) continue;\n\n if (fk.onDelete === 'setNull' && !column.nullable) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": onDelete setNull on foreign key column \"${colName}\" which is NOT NULL`,\n );\n }\n if (fk.onUpdate === 'setNull' && !column.nullable) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": onUpdate setNull on foreign key column \"${colName}\" which is NOT NULL`,\n );\n }\n if (fk.onDelete === 'setDefault' && !column.nullable && column.default === undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": onDelete setDefault on foreign key column \"${colName}\" which is NOT NULL and has no DEFAULT`,\n );\n }\n if (fk.onUpdate === 'setDefault' && !column.nullable && column.default === undefined) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": onUpdate setDefault on foreign key column \"${colName}\" which is NOT NULL and has no DEFAULT`,\n );\n }\n }\n }\n\n const seenCheckDefinitions = new Set<string>();\n for (const check of table.checks ?? []) {\n const signature = JSON.stringify({ column: check.column, valueSet: check.valueSet });\n if (seenCheckDefinitions.has(signature)) {\n errors.push(\n `Namespace \"${namespaceId}\" table \"${tableName}\": duplicate check constraint definition on column \"${check.column}\"`,\n );\n continue;\n }\n seenCheckDefinitions.add(signature);\n }\n }\n\n return errors;\n}\n\n/**\n * SQL storage logical-consistency checks: every model.storage.table\n * resolves to a real table, every model.storage.fields[*].column\n * resolves to a real column, and value-object fields land on JSON-native\n * columns. Throws `ContractValidationError` on the first mismatch.\n */\nexport function validateModelStorageReferences(contract: Contract<SqlStorage>): void {\n for (const [namespaceId, namespace] of Object.entries(contract.domain.namespaces)) {\n const models = namespace.models as Record<string, ContractModel<SqlModelStorage>>;\n for (const [modelName, model] of Object.entries(models)) {\n const qualifiedName = `${namespaceId}:${modelName}`;\n const storageNamespaceId = model.storage.namespaceId;\n if (storageNamespaceId !== namespaceId) {\n throw new ContractValidationError(\n `Model \"${qualifiedName}\" storage.namespaceId \"${storageNamespaceId}\" does not match domain namespace \"${namespaceId}\"`,\n 'storage',\n );\n }\n\n const storageTable = model.storage.table;\n const storageNs = contract.storage.namespaces[storageNamespaceId];\n const rawTable = storageNs?.entries.table?.[storageTable];\n if (rawTable === undefined) {\n throw new ContractValidationError(\n `Model \"${qualifiedName}\" references non-existent table \"${storageNamespaceId}.${storageTable}\"`,\n 'storage',\n );\n }\n\n const table = rawTable as StorageTable;\n\n const columnNames = new Set(Object.keys(table.columns));\n for (const [fieldName, field] of Object.entries(model.storage.fields)) {\n if (!columnNames.has(field.column)) {\n throw new ContractValidationError(\n `Model \"${qualifiedName}\" field \"${fieldName}\" references non-existent column \"${field.column}\" in table \"${storageTable}\"`,\n 'storage',\n );\n }\n }\n\n const JSON_NATIVE_TYPES = new Set(['json', 'jsonb']);\n for (const [fieldName, domainField] of Object.entries(model.fields ?? {})) {\n const f = domainField as ContractField;\n if (f.type?.kind !== 'valueObject') continue;\n const storageField = model.storage.fields[fieldName];\n if (!storageField) continue;\n const column = table.columns[storageField.column];\n if (!column) continue;\n if (!JSON_NATIVE_TYPES.has(column.nativeType)) {\n throw new ContractValidationError(\n `Model \"${qualifiedName}\" field \"${fieldName}\" is a value object but storage column \"${storageField.column}\" has nativeType \"${column.nativeType}\" (expected json or jsonb)`,\n 'storage',\n );\n }\n }\n }\n }\n}\n\n/**\n * Cross-table consistency checks for SQL storage: primary key, unique,\n * index, and foreign key column references resolve to real columns;\n * NOT NULL columns don't carry a literal `null` default; FK column\n * counts match their referenced columns. Throws on the first mismatch.\n */\nexport function validateSqlStorageConsistency(contract: Contract<SqlStorage>): void {\n for (const { namespaceId, tableName, table: rawTable } of eachStorageTable(contract.storage)) {\n const table = rawTable as StorageTable;\n const columnNames = new Set(Object.keys(table.columns));\n\n if (table.primaryKey) {\n for (const colName of table.primaryKey.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" primaryKey references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n }\n\n for (const unique of table.uniques) {\n for (const colName of unique.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" unique constraint references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n }\n\n for (const index of table.indexes) {\n for (const colName of index.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" index references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n }\n\n for (const check of table.checks ?? []) {\n if (!columnNames.has(check.column)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" check constraint \"${check.name}\" references non-existent column \"${check.column}\"`,\n 'storage',\n );\n }\n }\n\n for (const [colName, column] of Object.entries(table.columns)) {\n if (!column.nullable && column.default?.kind === 'literal' && column.default.value === null) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" column \"${colName}\" is NOT NULL but has a literal null default`,\n 'storage',\n );\n }\n }\n\n for (const fk of table.foreignKeys) {\n if (fk.source.namespaceId !== namespaceId || fk.source.tableName !== tableName) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" contains foreignKey with mismatched source coordinates (${fk.source.namespaceId}.${fk.source.tableName})`,\n 'storage',\n );\n }\n\n for (const colName of fk.source.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" foreignKey references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n\n if (fk.target.spaceId === undefined) {\n const targetNamespace = contract.storage.namespaces[fk.target.namespaceId];\n const referencedRaw = targetNamespace?.entries.table?.[fk.target.tableName];\n if (referencedRaw === undefined) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" foreignKey references non-existent table \"${fk.target.namespaceId}.${fk.target.tableName}\"`,\n 'storage',\n );\n }\n const referencedTable = referencedRaw as StorageTable;\n const referencedColumnNames = new Set(Object.keys(referencedTable.columns));\n for (const colName of fk.target.columns) {\n if (!referencedColumnNames.has(colName)) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" foreignKey references non-existent column \"${colName}\" in table \"${fk.target.tableName}\"`,\n 'storage',\n );\n }\n }\n }\n\n if (fk.source.columns.length !== fk.target.columns.length) {\n throw new ContractValidationError(\n `Namespace \"${namespaceId}\" table \"${tableName}\" foreignKey column count (${fk.source.columns.length}) does not match referenced column count (${fk.target.columns.length})`,\n 'storage',\n );\n }\n }\n }\n}\n\nexport interface ValidateSqlContractFullyOptions {\n /**\n * Precomputed structural schema to validate against. Built once at\n * serializer construction time when the family `ContractSerializer`\n * has folded pack-contributed `validatorSchema` fragments into the\n * per-namespace entry shape; absent for the family-default validator\n * path (no pack contributions). Falls back to the cached default\n * `SqlContractSchema` when omitted.\n */\n readonly contractSchema?: Type<unknown>;\n}\n\n/**\n * Full SQL contract validation: structural (arktype) +\n * framework-shared domain + SQL storage logical-consistency + SQL\n * storage semantic + model ↔ storage reference checks. Throws\n * `ContractValidationError` on the first failure. Returns the\n * validated flat-data shape; IR class hydration happens in the SPI\n * base on top of this helper.\n */\nexport function validateSqlContractFully<T extends Contract<SqlStorage>>(\n value: unknown,\n options?: ValidateSqlContractFullyOptions,\n): T {\n const stripped =\n typeof value === 'object' && value !== null\n ? (() => {\n const { schemaVersion: _, _generated: _g, ...rest } = value as Record<string, unknown>;\n return rest;\n })()\n : value;\n const schema = options?.contractSchema ?? SqlContractSchema;\n const validated = validateSqlContractStructure<T>(stripped, schema);\n validateContractDomain({\n roots: validated.roots,\n domain: validated.domain,\n });\n validateSqlStorageConsistency(validated);\n const semanticErrors = validateStorageSemantics(validated.storage);\n if (semanticErrors.length > 0) {\n throw new ContractValidationError(\n `Contract semantic validation failed: ${semanticErrors.join('; ')}`,\n 'storage',\n );\n }\n validateModelStorageReferences(validated);\n return validated;\n}\n"],"mappings":";;;;;;;;;AAgCA,MAAM,oBAAoB,KAAK,WAAW;AAC1C,MAAM,qBAAqB,KAAK,YAAY;AAC5C,MAAM,sBAAsB,KAAK,aAAa;AAC9C,MAAM,sBAAsB,KAAK,mDAAmD;AACpF,MAAM,oBAAoB,KAAK,QAAQ,CAAC,CAAC,QAAQ,OAAO,QAAQ;CAC9D,OAAO,8BAA8B,KAAK,KAAK,IAAI,OAAO,IAAI,OAAO,qBAAqB;AAC5F,CAAC;AAED,MAAa,6BAA6B,KAAK,QAA8B,CAAC,CAAC,KAAK;CAClF,MAAM;CACN,OAAO;AACT,CAAC;AAED,MAAa,8BAA8B,KAAK,QAA+B,CAAC,CAAC,KAAK;CACpF,MAAM;CACN,YAAY;AACd,CAAC;AAED,MAAa,sBAAsB,2BAA2B,GAAG,2BAA2B;AAE5F,MAAM,sCAAsC,KAAK;CAC/C,KAAK;CACL,MAAM;CACN,IAAI;CACJ,WAAW;AACb,CAAC;AAaD,MAAM,kBAAkB,KAAK;CAC3B,KAAK;CACL,eAAe;CACf,WAAW;EACT,KAAK;EACL,UAhBmC,KAAK;GAC1C,KAAK;GACL,KAAK;IACH,KAAK;IACL,OAAO;IACP,QAAQ;GACV;GACA,aAAa;GACb,aAAa;EACf,CAO2C,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS;CAC5D;AACF,CAAC;AAED,MAAM,2BAA2B,KAAK;CACpC,OAAO;CACP,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,YAAY;AACd,CAAC;AAED,MAAM,sBAAsB,KAAK;CAC/B,OAAO;CACP,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,YAAY;AACd,CAAC;AAED,MAAM,sBAAsB,KAAK;CAC/B,KAAK;CACL,YAAY;CACZ,SAAS;CACT,UAAU;CACV,eAAe;CACf,YAAY;CACZ,YAAY;CACZ,YAAY;CACZ,aAAa;AACf,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ;CACtB,IAAI,IAAI,eAAe,KAAA,KAAa,IAAI,YAAY,KAAA,GAClD,OAAO,IAAI,OAAO,sDAAsD;CAE1E,OAAO;AACT,CAAC;;AAiBD,MAAM,kCAV4B,KAC/B,QAA+D,CAAC,CAChE,KAAK;CACJ,MAAM;CACN,SAAS;CACT,YAAY;CACZ,eAAe;AACjB,CAG8D;;;;;;AAOhE,MAAa,wBAAwB,KAAK;CACxC,MAAM;CACN,QAAQ,KAAK,wEAAwE,CAAC,CACnF,MAAM,CAAC,CACP,SAAS;AACd,CAAC;;;;;AAMD,MAAa,qBAAqB,KAAK;CACrC,KAAK;CACL,SAAS;CACT,SAAS,KAAK;EACZ,MAAM;EACN,OAAO;CACT,CAAC,CAAC,CACC,MAAM,CAAC,CACP,SAAS;AACd,CAAC;AAED,MAAM,mBAAmB,KAAK,QAAyB,CAAC,CAAC,KAAK;CAC5D,SAAS,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;CACtC,SAAS;AACX,CAAC;AAED,MAAM,yBAAyB,KAAK,QAA+B,CAAC,CAAC,KAAK;CACxE,SAAS,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;CACtC,SAAS;AACX,CAAC;AAED,MAAa,cAAc,KAAK;CAC9B,SAAS,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;CACtC,SAAS;CACT,SAAS;CACT,YAAY;AACd,CAAC;AAED,MAAa,4BAA4B,KAAK;CAC5C,KAAK;CACL,aAAa;CACb,WAAW;CACX,SAAS,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;CACtC,YAAY;AACd,CAAC;AAED,MAAa,yBAAyB,KAAK;CACzC,KAAK;CACL,aAAa;CACb,WAAW;CACX,SAAS,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;AACxC,CAAC;AAED,MAAa,0BAA0B,KACpC,QAA2B,CAAC,CAC5B,KAAK,gEAAgE;AAExE,MAAa,mBAAmB,KAAK,QAAyB,CAAC,CAAC,KAAK;CACnE,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,aAAa;CACb,aAAa;CACb,YAAY;CACZ,OAAO;AACT,CAAC;AAED,MAAa,wBAAwB,KAAK;CACxC,KAAK;CACL,MAAM;CACN,QAAQ;CACR,UAAU;AACZ,CAAC;AAED,MAAM,qBAAqB,KAAK;CAC9B,KAAK;CACL,SAAS,KAAK,EAAE,YAAY,oBAAoB,CAAC;CACjD,eAAe;CACf,SAAS,uBAAuB,MAAM,CAAC,CAAC,SAAS;CACjD,SAAS,YAAY,MAAM,CAAC,CAAC,SAAS;CACtC,aAAa,iBAAiB,MAAM,CAAC,CAAC,SAAS;CAC/C,YAAY;CACZ,WAAW,sBAAsB,MAAM,CAAC,CAAC,SAAS;AACpD,CAAC;;;;;;;;AASD,SAAgB,6BACd,aACoC;CACpC,MAAM,WAAW,IAAI,IAA2B,CAC9C,CAAC,SAAS,OAAsB,kBAAkB,CAAC,GACnD,CAAC,YAAY,OAAsB,qBAAqB,CAAC,CAC3D,CAAC;CACD,IAAI,gBAAgB,KAAA,GAClB,KAAK,MAAM,CAAC,MAAM,WAAW,aAAa;EACxC,IAAI,SAAS,IAAI,IAAI,GACnB,MAAM,IAAI,MACR,8CAA8C,KAAK,iFACrD;EAEF,SAAS,IAAI,MAAM,MAAM;CAC3B;CAEF,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,2BACd,UACe;CACf,OAAO,KAAK;EACV,KAAK;EACL,IAAI;EACJ,SAAS;EACT,SAAS;CACX,CAAC,CAAC,CAAC,QAAQ,IAAI,QAAQ;EACrB,IAAI,CAAC,cAAc,GAAG,OAAO,GAC3B,OAAO,IAAI,OAAO,mBAAmB;EAEvC,KAAK,MAAM,CAAC,KAAK,aAAa,OAAO,QAAQ,GAAG,OAAO,GAAG;GACxD,MAAM,cAAc,SAAS,IAAI,GAAG;GACpC,IAAI,gBAAgB,KAAA,GAClB,OAAO,IAAI,OAAO,EAChB,UAAU,gBAAgB,IAAI,kBAAkB,GAAG,GAAG,mCACxD,CAAC;GAEH,IAAI,CAAC,cAAc,QAAQ,GACzB,OAAO,IAAI,OAAO,EAChB,UAAU,YAAY,IAAI,mBAAmB,GAAG,GAAG,qBACrD,CAAC;GAEH,KAAK,MAAM,GAAG,UAAU,OAAO,QAAQ,QAAQ,GAAG;IAChD,MAAM,SAAS,YAAY,KAAK;IAChC,IAAI,kBAAkB,KAAK,QACzB,OAAO,IAAI,OAAO,EAAE,UAAU,OAAO,QAAQ,CAAC;GAElD;EACF;EACA,OAAO;CACT,CAAC;AACH;;;;;;;AAQA,SAAgB,uBACd,UACe;CACf,MAAM,iBAAiB,2BAA2B,QAAQ;CAC1D,OAAO,KAAK;EACV,KAAK;EACL,aAAa;EACb,UAAU,KAAK,EAAE,YAAY,gCAAgC,CAAC;EAM9D,eAAe,KAAK,EAAE,YAAY,eAAe,CAAC;CACpD,CAAC;AACH;AAEA,MAAM,gBAAgB,uBAAuB,6BAA6B,CAAC;AAW3E,SAAS,iBAAiB,SAAgC;CACxD,OAAO,OAAO,QAAQ,QAAQ,UAAU,CAAC,CAAC,SAAS,CAAC,aAAa,QAC/D,OAAO,QAAQ,GAAG,QAAQ,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,YAAY;EACrE;EACA;EACA;CACF,EAAE,CACJ;AACF;AAEA,SAAS,cAAc,OAAkD;CACvE,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG,OAAO;CAChF,MAAM,QAAQ,OAAO,eAAe,KAAK;CACzC,OAAO,UAAU,OAAO,aAAa,UAAU;AACjD;AAEA,SAAS,mBAAmB,QAA+C;CACzE,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,KAAK,IAAI,KAAK,GAChB,OAAO;EAET,KAAK,IAAI,KAAK;CAChB;AAEF;AAEA,SAAS,oBAAoB,OAAyB;CACpD,IAAI,CAAC,cAAc,KAAK,GAAG,OAAO;CAClC,MAAM,OAAO,MAAM;CACnB,IAAI,SAAS,UAAU;EACrB,IAAI,OAAO,MAAM,eAAe,UAAU,OAAO;EACjD,MAAM,aAAa,MAAM;EACzB,IAAI,eAAe,KAAA,KAAa,CAAC,cAAc,UAAU,GAAG,OAAO;EACnE,OAAO;CACT;CACA,IAAI,SAAS,eACX,OAAO,OAAO,MAAM,YAAY;CAElC,IAAI,SAAS,SAAS;EACpB,MAAM,UAAU,MAAM;EACtB,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG,OAAO;EACpC,OAAO,QAAQ,OAAO,MAAM,oBAAoB,CAAC,CAAC;CACpD;CACA,OAAO;AACT;AAMA,MAAM,mBAAmB,KAAK;CAC5B,KAAK;CACL,UAAU;CACV,MAP8B,KAAK,SAAS,CAAC,CAAC,QAAQ,OAAO,QAC7D,oBAAoB,KAAK,IAAI,OAAO,IAAI,OAAO,0CAA0C,CAM7D;CAC5B,SAAS;CACT,SAAS;CACT,aAAa;AACf,CAAC;AAQD,MAAM,qBAAqB,KAAK;CAC9B,OAAO;CACP,aAAa;CACb,QAAQ,KAAK,EAAE,YATe,KAAK;EACnC,QAAQ;EACR,YAAY;EACZ,aAAa;CACf,CAKmD,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,gCAAgC,KAAK;CACzC,KAAK;CACL,OAAO;CACP,aAAa;CACb,eAAe,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;CAC5C,cAAc,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;CAC3C,eAAe,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;AAC9C,CAAC;AAED,MAAM,2BAA2B,KAAK;CACpC,KAAK;CACL,aAAa,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;CAC1C,cAAc,KAAK,OAAO,MAAM,CAAC,CAAC,SAAS;AAC7C,CAAC;AAED,MAAM,mCAAmC,KAAK;CAC5C,KAAK;CACL,IAAI;CACJ,aAAa;CACb,IAAI;CACJ,SAAS;AACX,CAAC;AAED,MAAM,oCAAoC,KAAK;CAC7C,KAAK;CACL,IAAI;CACJ,aAAa;CACb,IAAI;AACN,CAAC;AAED,MAAM,kCAAkC,iCAAiC,GACvE,iCACF;AAEA,MAAM,8BAA8B,KAAK;CACvC,KAAK;CACL,IAAI;CACJ,aAAa;AACf,CAAC;AAED,MAAM,yBAAyB,gCAAgC,GAAG,2BAA2B;AAE7F,MAAM,cAAc,KAAK;CACvB,SAAS;CACT,WAAW,KAAK,EAAE,YAAY,iBAAiB,CAAC;CAChD,cAAc,KAAK,EAAE,YAAY,uBAAuB,CAAC;CACzD,kBAAkB;CAClB,aAAa;CACb,SAAS;CACT,UAAU;AACZ,CAAC;AAED,MAAM,qBAAqB,KAAK,EAC9B,YAAY,UACd,CAAC;;;;;;AAOD,SAAgB,wBACd,UACe;CACf,MAAM,UAAU,uBAAuB,QAAQ;CAC/C,OAAO,KAAK;EACV,KAAK;EACL,QAAQ;EACR,cAAc;EACd,aAAa;EACb,aAAa;EACb,iBAAiB;EACjB,mBAAmB;EACnB,SAAS;EACT,yBAAyB;EACzB,UAAU,KAAK,EAAE,YAAY,qBAAqB,CAAC;EACnD,QAAQ,KAAK,EACX,YAAY,KAAK,EACf,YAAY,KAAK;GACf,QAAQ,KAAK,EAAE,YAAY,YAAY,CAAC;GACxC,iBAAiB;GACjB,SAAS,KAAK,EAAE,YAAY,mBAAmB,CAAC;EAClD,CAAC,EACH,CAAC,EACH,CAAC;EACD;EACA,cAAc;CAChB,CAAC;AACH;AAEA,MAAM,oBAAoB,wBAAwB,6BAA6B,CAAC;;;;;;;;AAehF,SAAgB,gBAAgB,OAA4B;CAC1D,MAAM,SAAS,cAAc,KAAK;CAClC,IAAI,kBAAkB,KAAK,QAAQ;EACjC,MAAM,WAAW,OAAO,KAAK,MAA2B,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI;EAC5E,MAAM,IAAI,MAAM,8BAA8B,UAAU;CAC1D;CAKA,MAAM,YAAY,UAGhB,MAAM;CACR,MAAM,aAAa,qBAAqB,UAAU,cAAc,CAAC,CAAC;CAMlE,MAAM,UAAU,WAAW,yBAAyB,oBAAoB;CACxE,OAAO,IAAI,WAAW;EACpB,aAAa,UAAU;EACvB,GAAG,UAAU,SAAS,UAAU,KAAK;EACrC,YAAY;GAAE,GAAG;IAAa,uBAAuB;EAAQ;CAC/D,CAAC;AACH;AAEA,SAAgB,cAAc,OAAyB;CACrD,MAAM,SAAS,YAAY,KAAK;CAChC,IAAI,kBAAkB,KAAK,QAAQ;EACjC,MAAM,WAAW,OAAO,KAAK,MAA2B,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI;EAC5E,MAAM,IAAI,MAAM,4BAA4B,UAAU;CACxD;CACA,OAAO;AACT;;;;;;;AAQA,SAAS,6BACP,OACA,gBACG;CACH,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,MAAM,IAAI,wBACR,kEACA,YACF;CAGF,MAAM,WAAW;CACjB,IAAI,SAAS,iBAAiB,KAAA,KAAa,SAAS,iBAAiB,OACnE,MAAM,IAAI,wBACR,8BAA8B,SAAS,gBACvC,YACF;CAGF,MAAM,iBAAiB,eAAe,KAAK;CAE3C,IAAI,0BAA0B,KAAK,QAEjC,MAAM,IAAI,wBACR,0CAFe,eAAe,KAAK,MAA2B,EAAE,OAAO,CAAC,CAAC,KAAK,IAE7B,KACjD,YACF;CAKF,OAAO;AACT;;;;;;;;;;;;;;AAeA,SAAgB,yBAAyB,SAA+B;CACtE,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,EAAE,aAAa,WAAW,OAAO,cAAc,iBAAiB,OAAO,GAAG;EACnF,MAAM,QAAQ;EACd,MAAM,+BAAe,IAAI,IAAsB;EAC/C,MAAM,uBAAuB,MAAc,SAA6B;GACtE,IAAI,CAAC,MAAM;GACX,aAAa,IAAI,MAAM,CAAC,GAAI,aAAa,IAAI,IAAI,KAAK,CAAC,GAAI,IAAI,CAAC;EAClE;EAEA,oBAAoB,eAAe,MAAM,YAAY,IAAI;EACzD,KAAK,MAAM,UAAU,MAAM,SACzB,oBAAoB,qBAAqB,OAAO,IAAI;EAEtD,KAAK,MAAM,SAAS,MAAM,SACxB,oBAAoB,SAAS,MAAM,IAAI;EAEzC,KAAK,MAAM,MAAM,MAAM,aACrB,oBAAoB,eAAe,GAAG,IAAI;EAE5C,KAAK,MAAM,SAAS,MAAM,UAAU,CAAC,GACnC,oBAAoB,oBAAoB,MAAM,IAAI;EAGpD,KAAK,MAAM,CAAC,MAAM,UAAU,cAC1B,IAAI,MAAM,SAAS,GACjB,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,mBAAmB,KAAK,gCAAgC,MAAM,KAAK,IAAI,EAAE,EAC1H;EAIJ,IAAI,MAAM,YAAY;GACpB,MAAM,kBAAkB,mBAAmB,MAAM,WAAW,OAAO;GACnE,IAAI,oBAAoB,KAAA,GACtB,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,4CAA4C,gBAAgB,EAC7G;GAGF,KAAK,MAAM,cAAc,MAAM,WAAW,SAExC,IADe,MAAM,QAAQ,WACnB,EAAE,aAAa,MACvB,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,yBAAyB,WAAW,oDACrF;EAGN;EAEA,MAAM,wCAAwB,IAAI,IAAY;EAC9C,KAAK,MAAM,UAAU,MAAM,SAAS;GAClC,MAAM,kBAAkB,mBAAmB,OAAO,OAAO;GACzD,IAAI,oBAAoB,KAAA,GACtB,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,kDAAkD,gBAAgB,EACnH;GAGF,MAAM,YAAY,KAAK,UAAU,EAAE,SAAS,OAAO,QAAQ,CAAC;GAC5D,IAAI,sBAAsB,IAAI,SAAS,GAAG;IACxC,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,wDAAwD,OAAO,QAAQ,KAAK,IAAI,EAAE,EACnI;IACA;GACF;GACA,sBAAsB,IAAI,SAAS;EACrC;EAEA,MAAM,eAAe,MACnB,IAAI,OAAO,YAAY,OAAO,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI;EAErF,MAAM,uCAAuB,IAAI,IAAY;EAC7C,KAAK,MAAM,SAAS,MAAM,SAAS;GACjC,MAAM,kBAAkB,mBAAmB,MAAM,OAAO;GACxD,IAAI,oBAAoB,KAAA,GACtB,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,sCAAsC,gBAAgB,EACvG;GAGF,MAAM,YAAY,KAAK,UAAU;IAC/B,SAAS,MAAM;IACf,MAAM,MAAM,QAAQ;IACpB,SAAS,YAAY,MAAM,OAAO;GACpC,CAAC;GACD,IAAI,qBAAqB,IAAI,SAAS,GAAG;IACvC,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,4CAA4C,MAAM,QAAQ,KAAK,IAAI,EAAE,EACtH;IACA;GACF;GACA,qBAAqB,IAAI,SAAS;EACpC;EAEA,MAAM,4CAA4B,IAAI,IAAY;EAClD,KAAK,MAAM,MAAM,MAAM,aAAa;GAClC,MAAM,YAAY,KAAK,UAAU;IAC/B,QAAQ,GAAG;IACX,QAAQ,GAAG;IACX,UAAU,GAAG,YAAY;IACzB,UAAU,GAAG,YAAY;IACzB,YAAY,GAAG;IACf,OAAO,GAAG;GACZ,CAAC;GACD,IAAI,0BAA0B,IAAI,SAAS,GAAG;IAC5C,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,kDAAkD,GAAG,OAAO,QAAQ,KAAK,IAAI,EAAE,EAChI;IACA;GACF;GACA,0BAA0B,IAAI,SAAS;EACzC;EAEA,KAAK,MAAM,MAAM,MAAM,aACrB,KAAK,MAAM,WAAW,GAAG,OAAO,SAAS;GACvC,MAAM,SAAS,MAAM,QAAQ;GAC7B,IAAI,CAAC,QAAQ;GAEb,IAAI,GAAG,aAAa,aAAa,CAAC,OAAO,UACvC,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,6CAA6C,QAAQ,oBACtG;GAEF,IAAI,GAAG,aAAa,aAAa,CAAC,OAAO,UACvC,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,6CAA6C,QAAQ,oBACtG;GAEF,IAAI,GAAG,aAAa,gBAAgB,CAAC,OAAO,YAAY,OAAO,YAAY,KAAA,GACzE,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,gDAAgD,QAAQ,uCACzG;GAEF,IAAI,GAAG,aAAa,gBAAgB,CAAC,OAAO,YAAY,OAAO,YAAY,KAAA,GACzE,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,gDAAgD,QAAQ,uCACzG;EAEJ;EAGF,MAAM,uCAAuB,IAAI,IAAY;EAC7C,KAAK,MAAM,SAAS,MAAM,UAAU,CAAC,GAAG;GACtC,MAAM,YAAY,KAAK,UAAU;IAAE,QAAQ,MAAM;IAAQ,UAAU,MAAM;GAAS,CAAC;GACnF,IAAI,qBAAqB,IAAI,SAAS,GAAG;IACvC,OAAO,KACL,cAAc,YAAY,WAAW,UAAU,sDAAsD,MAAM,OAAO,EACpH;IACA;GACF;GACA,qBAAqB,IAAI,SAAS;EACpC;CACF;CAEA,OAAO;AACT;;;;;;;AAQA,SAAgB,+BAA+B,UAAsC;CACnF,KAAK,MAAM,CAAC,aAAa,cAAc,OAAO,QAAQ,SAAS,OAAO,UAAU,GAAG;EACjF,MAAM,SAAS,UAAU;EACzB,KAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,MAAM,GAAG;GACvD,MAAM,gBAAgB,GAAG,YAAY,GAAG;GACxC,MAAM,qBAAqB,MAAM,QAAQ;GACzC,IAAI,uBAAuB,aACzB,MAAM,IAAI,wBACR,UAAU,cAAc,yBAAyB,mBAAmB,qCAAqC,YAAY,IACrH,SACF;GAGF,MAAM,eAAe,MAAM,QAAQ;GAEnC,MAAM,WADY,SAAS,QAAQ,WAAW,mBACpB,EAAE,QAAQ,QAAQ;GAC5C,IAAI,aAAa,KAAA,GACf,MAAM,IAAI,wBACR,UAAU,cAAc,mCAAmC,mBAAmB,GAAG,aAAa,IAC9F,SACF;GAGF,MAAM,QAAQ;GAEd,MAAM,cAAc,IAAI,IAAI,OAAO,KAAK,MAAM,OAAO,CAAC;GACtD,KAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,MAAM,QAAQ,MAAM,GAClE,IAAI,CAAC,YAAY,IAAI,MAAM,MAAM,GAC/B,MAAM,IAAI,wBACR,UAAU,cAAc,WAAW,UAAU,oCAAoC,MAAM,OAAO,cAAc,aAAa,IACzH,SACF;GAIJ,MAAM,oBAAoB,IAAI,IAAI,CAAC,QAAQ,OAAO,CAAC;GACnD,KAAK,MAAM,CAAC,WAAW,gBAAgB,OAAO,QAAQ,MAAM,UAAU,CAAC,CAAC,GAAG;IAEzE,IAAIA,YAAE,MAAM,SAAS,eAAe;IACpC,MAAM,eAAe,MAAM,QAAQ,OAAO;IAC1C,IAAI,CAAC,cAAc;IACnB,MAAM,SAAS,MAAM,QAAQ,aAAa;IAC1C,IAAI,CAAC,QAAQ;IACb,IAAI,CAAC,kBAAkB,IAAI,OAAO,UAAU,GAC1C,MAAM,IAAI,wBACR,UAAU,cAAc,WAAW,UAAU,0CAA0C,aAAa,OAAO,oBAAoB,OAAO,WAAW,6BACjJ,SACF;GAEJ;EACF;CACF;AACF;;;;;;;AAQA,SAAgB,8BAA8B,UAAsC;CAClF,KAAK,MAAM,EAAE,aAAa,WAAW,OAAO,cAAc,iBAAiB,SAAS,OAAO,GAAG;EAC5F,MAAM,QAAQ;EACd,MAAM,cAAc,IAAI,IAAI,OAAO,KAAK,MAAM,OAAO,CAAC;EAEtD,IAAI,MAAM;QACH,MAAM,WAAW,MAAM,WAAW,SACrC,IAAI,CAAC,YAAY,IAAI,OAAO,GAC1B,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,+CAA+C,QAAQ,IACtG,SACF;EAAA;EAKN,KAAK,MAAM,UAAU,MAAM,SACzB,KAAK,MAAM,WAAW,OAAO,SAC3B,IAAI,CAAC,YAAY,IAAI,OAAO,GAC1B,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,sDAAsD,QAAQ,IAC7G,SACF;EAKN,KAAK,MAAM,SAAS,MAAM,SACxB,KAAK,MAAM,WAAW,MAAM,SAC1B,IAAI,CAAC,YAAY,IAAI,OAAO,GAC1B,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,0CAA0C,QAAQ,IACjG,SACF;EAKN,KAAK,MAAM,SAAS,MAAM,UAAU,CAAC,GACnC,IAAI,CAAC,YAAY,IAAI,MAAM,MAAM,GAC/B,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,sBAAsB,MAAM,KAAK,oCAAoC,MAAM,OAAO,IACjI,SACF;EAIJ,KAAK,MAAM,CAAC,SAAS,WAAW,OAAO,QAAQ,MAAM,OAAO,GAC1D,IAAI,CAAC,OAAO,YAAY,OAAO,SAAS,SAAS,aAAa,OAAO,QAAQ,UAAU,MACrF,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,YAAY,QAAQ,+CACnE,SACF;EAIJ,KAAK,MAAM,MAAM,MAAM,aAAa;GAClC,IAAI,GAAG,OAAO,gBAAgB,eAAe,GAAG,OAAO,cAAc,WACnE,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,4DAA4D,GAAG,OAAO,YAAY,GAAG,GAAG,OAAO,UAAU,IACxJ,SACF;GAGF,KAAK,MAAM,WAAW,GAAG,OAAO,SAC9B,IAAI,CAAC,YAAY,IAAI,OAAO,GAC1B,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,+CAA+C,QAAQ,IACtG,SACF;GAIJ,IAAI,GAAG,OAAO,YAAY,KAAA,GAAW;IAEnC,MAAM,gBADkB,SAAS,QAAQ,WAAW,GAAG,OAAO,YACzB,EAAE,QAAQ,QAAQ,GAAG,OAAO;IACjE,IAAI,kBAAkB,KAAA,GACpB,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,8CAA8C,GAAG,OAAO,YAAY,GAAG,GAAG,OAAO,UAAU,IAC1I,SACF;IAGF,MAAM,wBAAwB,IAAI,IAAI,OAAO,KAAKC,cAAgB,OAAO,CAAC;IAC1E,KAAK,MAAM,WAAW,GAAG,OAAO,SAC9B,IAAI,CAAC,sBAAsB,IAAI,OAAO,GACpC,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,+CAA+C,QAAQ,cAAc,GAAG,OAAO,UAAU,IACxI,SACF;GAGN;GAEA,IAAI,GAAG,OAAO,QAAQ,WAAW,GAAG,OAAO,QAAQ,QACjD,MAAM,IAAI,wBACR,cAAc,YAAY,WAAW,UAAU,6BAA6B,GAAG,OAAO,QAAQ,OAAO,4CAA4C,GAAG,OAAO,QAAQ,OAAO,IAC1K,SACF;EAEJ;CACF;AACF;;;;;;;;;AAsBA,SAAgB,yBACd,OACA,SACG;CASH,MAAM,YAAY,6BAPhB,OAAO,UAAU,YAAY,UAAU,cAC5B;EACL,MAAM,EAAE,eAAe,GAAG,YAAY,IAAI,GAAG,SAAS;EACtD,OAAO;CACT,EAAA,CAAG,IACH,OACS,SAAS,kBAAkB,iBACwB;CAClE,uBAAuB;EACrB,OAAO,UAAU;EACjB,QAAQ,UAAU;CACpB,CAAC;CACD,8BAA8B,SAAS;CACvC,MAAM,iBAAiB,yBAAyB,UAAU,OAAO;CACjE,IAAI,eAAe,SAAS,GAC1B,MAAM,IAAI,wBACR,wCAAwC,eAAe,KAAK,IAAI,KAChE,SACF;CAEF,+BAA+B,SAAS;CACxC,OAAO;AACT"}
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-contract",
|
|
3
|
-
"version": "0.13.0-dev.
|
|
3
|
+
"version": "0.13.0-dev.30",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "SQL contract types, validators, and IR factories for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/contract": "0.13.0-dev.
|
|
10
|
-
"@prisma-next/framework-components": "0.13.0-dev.
|
|
11
|
-
"@prisma-next/utils": "0.13.0-dev.
|
|
9
|
+
"@prisma-next/contract": "0.13.0-dev.30",
|
|
10
|
+
"@prisma-next/framework-components": "0.13.0-dev.30",
|
|
11
|
+
"@prisma-next/utils": "0.13.0-dev.30",
|
|
12
12
|
"arktype": "^2.2.0"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@prisma-next/test-utils": "0.13.0-dev.
|
|
16
|
-
"@prisma-next/tsconfig": "0.13.0-dev.
|
|
17
|
-
"@prisma-next/tsdown": "0.13.0-dev.
|
|
15
|
+
"@prisma-next/test-utils": "0.13.0-dev.30",
|
|
16
|
+
"@prisma-next/tsconfig": "0.13.0-dev.30",
|
|
17
|
+
"@prisma-next/tsdown": "0.13.0-dev.30",
|
|
18
18
|
"tsdown": "0.22.1",
|
|
19
19
|
"typescript": "5.9.3",
|
|
20
20
|
"vitest": "4.1.8"
|
package/src/exports/types.ts
CHANGED
|
@@ -13,7 +13,6 @@ export type {
|
|
|
13
13
|
ForeignKeyOptions,
|
|
14
14
|
ForeignKeyReferenceInput,
|
|
15
15
|
IndexInput,
|
|
16
|
-
PostgresEnumStorageEntry,
|
|
17
16
|
PrimaryKeyInput,
|
|
18
17
|
QueryOperationReturn,
|
|
19
18
|
QueryOperationSelfSpec,
|
|
@@ -25,6 +24,8 @@ export type {
|
|
|
25
24
|
SqlControlDriverInstance,
|
|
26
25
|
SqlModelFieldStorage,
|
|
27
26
|
SqlModelStorage,
|
|
27
|
+
SqlNamespace,
|
|
28
|
+
SqlNamespaceEntries,
|
|
28
29
|
SqlNamespaceTablesInput,
|
|
29
30
|
SqlQueryOperationTypes,
|
|
30
31
|
SqlStorageInput,
|
|
@@ -49,9 +50,7 @@ export {
|
|
|
49
50
|
ForeignKey,
|
|
50
51
|
ForeignKeyReference,
|
|
51
52
|
Index,
|
|
52
|
-
isPostgresEnumStorageEntry,
|
|
53
53
|
isStorageTypeInstance,
|
|
54
|
-
POSTGRES_ENUM_KIND,
|
|
55
54
|
PrimaryKey,
|
|
56
55
|
SqlNode,
|
|
57
56
|
SqlStorage,
|
|
@@ -59,7 +58,6 @@ export {
|
|
|
59
58
|
StorageColumn,
|
|
60
59
|
StorageTable,
|
|
61
60
|
StorageValueSet,
|
|
62
|
-
storageTableAt,
|
|
63
61
|
toStorageTypeInstance,
|
|
64
62
|
UniqueConstraint,
|
|
65
63
|
} from '../types';
|
|
@@ -2,15 +2,14 @@ import { ContractValidationError } from '@prisma-next/contract/contract-validati
|
|
|
2
2
|
import type { Contract } from '@prisma-next/contract/types';
|
|
3
3
|
import { type } from 'arktype';
|
|
4
4
|
import type { IndexTypeRegistry } from './index-types';
|
|
5
|
-
import type { SqlStorage
|
|
5
|
+
import type { SqlStorage } from './types';
|
|
6
6
|
|
|
7
7
|
export function validateIndexTypes(
|
|
8
8
|
contract: Contract<SqlStorage>,
|
|
9
9
|
indexTypeRegistry: IndexTypeRegistry,
|
|
10
10
|
): void {
|
|
11
11
|
for (const [namespaceId, ns] of Object.entries(contract.storage.namespaces)) {
|
|
12
|
-
for (const [tableName,
|
|
13
|
-
const table = rawTable as StorageTable;
|
|
12
|
+
for (const [tableName, table] of Object.entries(ns.entries.table ?? {})) {
|
|
14
13
|
for (const index of table.indexes) {
|
|
15
14
|
if (index.type === undefined && index.options !== undefined) {
|
|
16
15
|
throw new ContractValidationError(
|
|
@@ -4,11 +4,12 @@ import {
|
|
|
4
4
|
NamespaceBase,
|
|
5
5
|
UNBOUND_NAMESPACE_ID,
|
|
6
6
|
} from '@prisma-next/framework-components/ir';
|
|
7
|
-
import { blindCast
|
|
8
|
-
import
|
|
7
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
8
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
9
|
+
import type { SqlNamespace, SqlNamespaceEntries, SqlNamespaceTablesInput } from './sql-storage';
|
|
9
10
|
import { SqlUnboundNamespace } from './sql-unbound-namespace';
|
|
10
|
-
import { StorageTable } from './storage-table';
|
|
11
|
-
import { StorageValueSet } from './storage-value-set';
|
|
11
|
+
import { StorageTable, type StorageTableInput } from './storage-table';
|
|
12
|
+
import { StorageValueSet, type StorageValueSetInput } from './storage-value-set';
|
|
12
13
|
|
|
13
14
|
const SQL_NAMESPACE_KIND = 'sql-namespace' as const;
|
|
14
15
|
|
|
@@ -27,39 +28,63 @@ class SqlBoundNamespace extends NamespaceBase {
|
|
|
27
28
|
declare readonly kind: string;
|
|
28
29
|
|
|
29
30
|
readonly id: string;
|
|
30
|
-
readonly entries:
|
|
31
|
-
readonly table: Readonly<Record<string, StorageTable>>;
|
|
32
|
-
readonly valueSet?: Readonly<Record<string, StorageValueSet>>;
|
|
33
|
-
}>;
|
|
31
|
+
readonly entries: SqlNamespaceEntries;
|
|
34
32
|
|
|
35
33
|
static fromTablesInput(input: SqlNamespaceTablesInput): SqlNamespace {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
const tableKind = input.entries['table'];
|
|
35
|
+
const tableCount = tableKind !== undefined ? Object.keys(tableKind).length : 0;
|
|
36
|
+
const valueSetKind = input.entries['valueSet'];
|
|
37
|
+
const hasValueSets = valueSetKind !== undefined && Object.keys(valueSetKind).length > 0;
|
|
38
|
+
const hasUnknownKinds = Object.keys(input.entries).some(
|
|
39
|
+
(kind) => kind !== 'table' && kind !== 'valueSet',
|
|
40
|
+
);
|
|
41
|
+
if (
|
|
42
|
+
input.id === UNBOUND_NAMESPACE_ID &&
|
|
43
|
+
tableCount === 0 &&
|
|
44
|
+
!hasValueSets &&
|
|
45
|
+
!hasUnknownKinds
|
|
46
|
+
) {
|
|
47
|
+
return SqlUnboundNamespace.instance;
|
|
41
48
|
}
|
|
42
|
-
return
|
|
49
|
+
return new SqlBoundNamespace(input);
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
private constructor(input: SqlNamespaceTablesInput) {
|
|
46
53
|
super();
|
|
47
54
|
this.id = input.id;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Object.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
|
|
56
|
+
const carried: Record<string, Readonly<Record<string, unknown>>> = {};
|
|
57
|
+
let table: Readonly<Record<string, StorageTable>> = Object.freeze({});
|
|
58
|
+
let valueSet: Readonly<Record<string, StorageValueSet>> | undefined;
|
|
59
|
+
for (const [kind, rawMap] of Object.entries(input.entries)) {
|
|
60
|
+
if (kind === 'table') {
|
|
61
|
+
const tableMap: Record<string, StorageTable> = {};
|
|
62
|
+
for (const [name, v] of Object.entries(
|
|
63
|
+
blindCast<
|
|
64
|
+
Record<string, StorageTableInput>,
|
|
65
|
+
'entries[table] holds StorageTableInput by construction'
|
|
66
|
+
>(rawMap),
|
|
67
|
+
)) {
|
|
68
|
+
tableMap[name] = new StorageTable(v);
|
|
69
|
+
}
|
|
70
|
+
table = Object.freeze(tableMap);
|
|
71
|
+
} else if (kind === 'valueSet') {
|
|
72
|
+
const vsMap: Record<string, StorageValueSet> = {};
|
|
73
|
+
for (const [name, v] of Object.entries(
|
|
74
|
+
blindCast<
|
|
75
|
+
Record<string, StorageValueSetInput>,
|
|
76
|
+
'entries[valueSet] holds StorageValueSetInput by construction'
|
|
77
|
+
>(rawMap),
|
|
78
|
+
)) {
|
|
79
|
+
vsMap[name] = new StorageValueSet(v);
|
|
80
|
+
}
|
|
81
|
+
valueSet = Object.freeze(vsMap);
|
|
82
|
+
} else {
|
|
83
|
+
carried[kind] = Object.freeze(rawMap);
|
|
84
|
+
}
|
|
62
85
|
}
|
|
86
|
+
|
|
87
|
+
this.entries = Object.freeze({ ...carried, table, ...ifDefined('valueSet', valueSet) });
|
|
63
88
|
Object.defineProperty(this, 'kind', {
|
|
64
89
|
value: SQL_NAMESPACE_KIND,
|
|
65
90
|
writable: false,
|
|
@@ -69,6 +94,14 @@ class SqlBoundNamespace extends NamespaceBase {
|
|
|
69
94
|
freezeNode(this);
|
|
70
95
|
}
|
|
71
96
|
|
|
97
|
+
get table(): Readonly<Record<string, StorageTable>> {
|
|
98
|
+
return this.entries.table ?? Object.freeze({});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get valueSet(): Readonly<Record<string, StorageValueSet>> | undefined {
|
|
102
|
+
return this.entries.valueSet;
|
|
103
|
+
}
|
|
104
|
+
|
|
72
105
|
qualifyTable(tableName: string): string {
|
|
73
106
|
if (this.id === UNBOUND_NAMESPACE_ID) {
|
|
74
107
|
return `"${tableName}"`;
|
|
@@ -88,10 +121,7 @@ export function buildSqlNamespaceMap(
|
|
|
88
121
|
Object.entries(namespaces).map(([nsKey, ns]) => [
|
|
89
122
|
nsKey,
|
|
90
123
|
isMaterializedSqlNamespace(ns)
|
|
91
|
-
?
|
|
92
|
-
SqlNamespace,
|
|
93
|
-
'a materialised SQL-family namespace entry in a namespace map is a SqlNamespace'
|
|
94
|
-
>(ns)
|
|
124
|
+
? ns
|
|
95
125
|
: SqlBoundNamespace.fromTablesInput(
|
|
96
126
|
blindCast<
|
|
97
127
|
SqlNamespaceTablesInput,
|
package/src/ir/sql-node.ts
CHANGED
|
@@ -41,8 +41,8 @@ export abstract class SqlNode extends IRNodeBase {
|
|
|
41
41
|
value: 'sql',
|
|
42
42
|
writable: false,
|
|
43
43
|
enumerable: false,
|
|
44
|
-
// configurable so per-leaf subclasses (e.g.
|
|
45
|
-
//
|
|
44
|
+
// configurable so per-leaf subclasses (e.g. StorageValueSet)
|
|
45
|
+
// can override `kind` with their narrower
|
|
46
46
|
// enumerable literal via a class-field initializer. SqlNode
|
|
47
47
|
// itself never needs to mutate the property again, so
|
|
48
48
|
// configurability has no surface impact at this layer.
|
package/src/ir/sql-storage.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { StorageHashBase } from '@prisma-next/contract/types';
|
|
2
2
|
import { freezeNode, type Namespace, type Storage } from '@prisma-next/framework-components/ir';
|
|
3
3
|
import { SqlNode } from './sql-node';
|
|
4
|
-
import type { StorageTable
|
|
4
|
+
import type { StorageTable } from './storage-table';
|
|
5
5
|
import {
|
|
6
6
|
isStorageTypeInstance,
|
|
7
7
|
type StorageTypeInstance,
|
|
8
8
|
type StorageTypeInstanceInput,
|
|
9
9
|
toStorageTypeInstance,
|
|
10
10
|
} from './storage-type-instance';
|
|
11
|
-
import type { StorageValueSet
|
|
11
|
+
import type { StorageValueSet } from './storage-value-set';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Polymorphic value type for document-scoped `SqlStorage.types` entries
|
|
@@ -21,10 +21,7 @@ export type SqlStorageTypeEntry = StorageTypeInstance | StorageTypeInstanceInput
|
|
|
21
21
|
|
|
22
22
|
export interface SqlNamespaceTablesInput {
|
|
23
23
|
readonly id: string;
|
|
24
|
-
readonly entries:
|
|
25
|
-
readonly table: Record<string, StorageTable | StorageTableInput>;
|
|
26
|
-
readonly valueSet?: Record<string, StorageValueSet | StorageValueSetInput>;
|
|
27
|
-
};
|
|
24
|
+
readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
|
|
28
25
|
}
|
|
29
26
|
|
|
30
27
|
export interface SqlStorageInput<THash extends string = string> {
|
|
@@ -54,17 +51,26 @@ export interface SqlStorageInput<THash extends string = string> {
|
|
|
54
51
|
* the per-target serializer's responsibility (so the family base does
|
|
55
52
|
* not import target-specific subclasses).
|
|
56
53
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
54
|
+
/**
|
|
55
|
+
* The typed `entries` shape for SQL family namespaces. The open dictionary
|
|
56
|
+
* is intersected with optional known-kind maps so that `ns.entries.table`
|
|
57
|
+
* and `ns.entries.valueSet` resolve without a cast, while unknown pack-
|
|
58
|
+
* contributed kinds remain valid (the `Record` part allows any string key).
|
|
59
|
+
*/
|
|
60
|
+
export type SqlNamespaceEntries = Readonly<Record<string, Readonly<Record<string, unknown>>>> & {
|
|
61
|
+
readonly table?: Readonly<Record<string, StorageTable>>;
|
|
62
|
+
readonly valueSet?: Readonly<Record<string, StorageValueSet>>;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* SQL family namespace. `entries` is the open ADR 224 dictionary —
|
|
67
|
+
* `entries[entityKind][entityName]` addresses any entity. Emitted
|
|
68
|
+
* contract literals satisfy this structurally (no prototype getters
|
|
69
|
+
* needed). For typed access to specific kinds, use the class getters
|
|
70
|
+
* on the concretion or `ns.entries.table` / `ns.entries.valueSet` directly.
|
|
71
|
+
*/
|
|
63
72
|
export type SqlNamespace = Namespace & {
|
|
64
|
-
readonly entries:
|
|
65
|
-
readonly table: Readonly<Record<string, StorageTable>>;
|
|
66
|
-
readonly valueSet?: Readonly<Record<string, StorageValueSet>>;
|
|
67
|
-
}>;
|
|
73
|
+
readonly entries: SqlNamespaceEntries;
|
|
68
74
|
/**
|
|
69
75
|
* Render a dialect-qualified table reference for runtime SQL emission.
|
|
70
76
|
* Present on materialised target concretions (`PostgresSchema`,
|
|
@@ -94,14 +100,6 @@ export class SqlStorage<THash extends string = string> extends SqlNode implement
|
|
|
94
100
|
}
|
|
95
101
|
}
|
|
96
102
|
|
|
97
|
-
export function storageTableAt(
|
|
98
|
-
storage: SqlStorage,
|
|
99
|
-
namespaceId: string,
|
|
100
|
-
tableName: string,
|
|
101
|
-
): StorageTable | undefined {
|
|
102
|
-
return storage.namespaces[namespaceId]?.entries.table[tableName];
|
|
103
|
-
}
|
|
104
|
-
|
|
105
103
|
/**
|
|
106
104
|
* Strict polymorphic-slot dispatch for `SqlStorage.types` entries.
|
|
107
105
|
* Every entry must carry a `kind: 'codec-instance'` discriminator or
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
NamespaceBase,
|
|
4
4
|
UNBOUND_NAMESPACE_ID,
|
|
5
5
|
} from '@prisma-next/framework-components/ir';
|
|
6
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
7
|
+
import type { SqlNamespaceEntries } from './sql-storage';
|
|
6
8
|
import type { StorageTable } from './storage-table';
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -40,9 +42,12 @@ export class SqlUnboundNamespace extends NamespaceBase {
|
|
|
40
42
|
static readonly instance: SqlUnboundNamespace = new SqlUnboundNamespace();
|
|
41
43
|
|
|
42
44
|
readonly id = UNBOUND_NAMESPACE_ID;
|
|
43
|
-
readonly entries:
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
readonly entries: SqlNamespaceEntries = Object.freeze({
|
|
46
|
+
table: blindCast<
|
|
47
|
+
Readonly<Record<string, StorageTable>>,
|
|
48
|
+
'empty frozen map is a valid Readonly<Record<string, StorageTable>>'
|
|
49
|
+
>(Object.freeze({})),
|
|
50
|
+
});
|
|
46
51
|
declare readonly kind: string;
|
|
47
52
|
|
|
48
53
|
private constructor() {
|
|
@@ -56,6 +61,13 @@ export class SqlUnboundNamespace extends NamespaceBase {
|
|
|
56
61
|
freezeNode(this);
|
|
57
62
|
}
|
|
58
63
|
|
|
64
|
+
get table(): Readonly<Record<string, StorageTable>> {
|
|
65
|
+
return blindCast<
|
|
66
|
+
Readonly<Record<string, StorageTable>>,
|
|
67
|
+
'entries[table] holds only StorageTable by construction'
|
|
68
|
+
>(this.entries['table']);
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
qualifyTable(tableName: string): string {
|
|
60
72
|
return `"${tableName}"`;
|
|
61
73
|
}
|
|
@@ -14,8 +14,8 @@ export const CODEC_INSTANCE_KIND = 'codec-instance' as const;
|
|
|
14
14
|
* in `SqlStorage.types`. These are plain object literals — there is no
|
|
15
15
|
* runtime IR class, the JSON envelope round-trips through the slot
|
|
16
16
|
* unchanged. The `kind: 'codec-instance'` discriminator is the dispatch
|
|
17
|
-
* key that distinguishes codec-typed entries from class-instance
|
|
18
|
-
*
|
|
17
|
+
* key that distinguishes codec-typed entries from any class-instance
|
|
18
|
+
* kinds a target pack contributes to the polymorphic slot.
|
|
19
19
|
*/
|
|
20
20
|
export interface StorageTypeInstance extends StorageType {
|
|
21
21
|
readonly kind: typeof CODEC_INSTANCE_KIND;
|
|
@@ -54,7 +54,7 @@ export function toStorageTypeInstance(input: StorageTypeInstanceInput): StorageT
|
|
|
54
54
|
/**
|
|
55
55
|
* Type-guard for codec-typed entries on the polymorphic
|
|
56
56
|
* `SqlStorage.types` slot. Distinguishes `StorageTypeInstance` from
|
|
57
|
-
* class-instance kinds
|
|
57
|
+
* any class-instance kinds a target pack contributes.
|
|
58
58
|
*/
|
|
59
59
|
export function isStorageTypeInstance(value: unknown): value is StorageTypeInstance {
|
|
60
60
|
if (typeof value !== 'object' || value === null) return false;
|