@prisma-next/sql-contract-psl 0.13.0-dev.4 → 0.13.0-dev.40
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/index.d.mts +3 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{interpreter-B_KtZusL.mjs → interpreter-B0BsCLKT.mjs} +110 -96
- package/dist/interpreter-B0BsCLKT.mjs.map +1 -0
- package/dist/provider.d.mts +1 -1
- package/dist/provider.mjs +5 -3
- package/dist/provider.mjs.map +1 -1
- package/package.json +12 -12
- package/src/interpreter.ts +91 -130
- package/src/provider.ts +2 -0
- package/src/psl-column-resolution.ts +1 -1
- package/src/psl-field-resolution.ts +90 -14
- package/dist/interpreter-B_KtZusL.mjs.map +0 -1
package/dist/provider.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ControlPolicy } from "@prisma-next/contract/types";
|
|
2
|
-
import { SqlNamespaceTablesInput } from "@prisma-next/sql-contract/types";
|
|
3
2
|
import { ContractConfig } from "@prisma-next/config/config-types";
|
|
4
3
|
import { ExtensionPackRef, TargetPackRef } from "@prisma-next/framework-components/components";
|
|
5
4
|
import { Namespace } from "@prisma-next/framework-components/ir";
|
|
5
|
+
import { SqlNamespaceTablesInput } from "@prisma-next/sql-contract/types";
|
|
6
6
|
|
|
7
7
|
//#region src/provider.d.ts
|
|
8
8
|
interface PrismaContractOptions {
|
package/dist/provider.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as interpretPslDocumentToSqlContract } from "./interpreter-
|
|
1
|
+
import { t as interpretPslDocumentToSqlContract } from "./interpreter-B0BsCLKT.mjs";
|
|
2
2
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
3
3
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
4
4
|
import { parsePslDocument } from "@prisma-next/psl-parser";
|
|
@@ -60,7 +60,8 @@ function prismaContract(schemaPath, options) {
|
|
|
60
60
|
}
|
|
61
61
|
const document = parsePslDocument({
|
|
62
62
|
schema,
|
|
63
|
-
sourceId: schemaPath
|
|
63
|
+
sourceId: schemaPath,
|
|
64
|
+
pslBlockDescriptors: context.authoringContributions.pslBlockDescriptors
|
|
64
65
|
});
|
|
65
66
|
const scalarTypeDescriptors = buildColumnDescriptorMap(context.scalarTypeDescriptors, context.codecLookup);
|
|
66
67
|
const interpreted = interpretPslDocumentToSqlContract({
|
|
@@ -72,7 +73,8 @@ function prismaContract(schemaPath, options) {
|
|
|
72
73
|
composedExtensionContracts: context.composedExtensionContracts,
|
|
73
74
|
...ifDefined("composedExtensionPackRefs", options.composedExtensionPackRefs?.length ? options.composedExtensionPackRefs : void 0),
|
|
74
75
|
controlMutationDefaults: context.controlMutationDefaults,
|
|
75
|
-
...ifDefined("createNamespace", options.createNamespace)
|
|
76
|
+
...ifDefined("createNamespace", options.createNamespace),
|
|
77
|
+
codecLookup: context.codecLookup
|
|
76
78
|
});
|
|
77
79
|
if (!interpreted.ok) return interpreted;
|
|
78
80
|
return ok(applySpecifierDefaultControlPolicy(interpreted.value, options.defaultControlPolicy));
|
package/dist/provider.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.mjs","names":[],"sources":["../src/provider.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { ContractConfig } from '@prisma-next/config/config-types';\nimport { applySpecifierDefaultControlPolicy } from '@prisma-next/contract/apply-specifier-default-control-policy';\nimport type { ControlPolicy } from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';\nimport type { Namespace } from '@prisma-next/framework-components/ir';\nimport { parsePslDocument } from '@prisma-next/psl-parser';\nimport type { SqlNamespaceTablesInput } from '@prisma-next/sql-contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { basename, extname } from 'pathe';\nimport { interpretPslDocumentToSqlContract } from './interpreter';\nimport type { ColumnDescriptor } from './psl-column-resolution';\n\nexport interface PrismaContractOptions {\n readonly output?: string;\n readonly target: TargetPackRef<'sql', string>;\n readonly composedExtensionPackRefs?: readonly ExtensionPackRef<'sql', string>[];\n readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;\n readonly defaultControlPolicy?: ControlPolicy;\n}\n\n/**\n * Derives the emit output path from the schema input path so artefacts land\n * colocated with the source (e.g. `src/contract/schema.prisma` →\n * `src/contract/contract.json`). The provider owns this because it is the\n * only layer that knows the input path; the upstream `normalizeContractConfig`\n * default is a last-resort fallback for providers that don't carry one.\n */\nfunction defaultOutputFromSchemaPath(schemaPath: string): string {\n const ext = extname(schemaPath);\n if (ext.length === 0) return `${schemaPath}.json`;\n const base = schemaPath.slice(0, -ext.length);\n // PSL schemas commonly use `schema.prisma`; the emitted JSON is called\n // `contract.json` to mirror the rest of the toolchain, not `schema.json`.\n // Match only the exact basename `schema` so files like `my-schema.prisma`\n // are not silently rewritten to `my-contract.json`.\n if (basename(base) === 'schema') {\n return `${base.slice(0, -'schema'.length)}contract.json`;\n }\n return `${base}.json`;\n}\n\nfunction buildColumnDescriptorMap(\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n codecLookup: CodecLookup,\n): ReadonlyMap<string, ColumnDescriptor> {\n const result = new Map<string, ColumnDescriptor>();\n for (const [typeName, codecId] of scalarTypeDescriptors) {\n const nativeType = codecLookup.targetTypesFor(codecId)?.[0];\n if (nativeType === undefined) continue;\n result.set(typeName, { codecId, nativeType });\n }\n return result;\n}\n\nexport function prismaContract(schemaPath: string, options: PrismaContractOptions): ContractConfig {\n return {\n source: {\n inputs: [schemaPath],\n load: async (context) => {\n const [absoluteSchemaPath] = context.resolvedInputs;\n if (absoluteSchemaPath === undefined) {\n throw new Error(\n 'prismaContract: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.',\n );\n }\n let schema: string;\n try {\n schema = await readFile(absoluteSchemaPath, 'utf-8');\n } catch (error) {\n const message = String(error);\n return notOk({\n summary: `Failed to read Prisma schema at \"${schemaPath}\"`,\n diagnostics: [\n {\n code: 'PSL_SCHEMA_READ_FAILED',\n message,\n sourceId: schemaPath,\n },\n ],\n meta: { schemaPath, absoluteSchemaPath, cause: message },\n });\n }\n\n const document = parsePslDocument({\n schema,\n sourceId: schemaPath,\n });\n\n const scalarTypeDescriptors = buildColumnDescriptorMap(\n context.scalarTypeDescriptors,\n context.codecLookup,\n );\n\n const interpreted = interpretPslDocumentToSqlContract({\n document,\n target: options.target,\n authoringContributions: context.authoringContributions,\n scalarTypeDescriptors,\n ...ifDefined(\n 'composedExtensionPacks',\n context.composedExtensionPacks.length > 0\n ? [...context.composedExtensionPacks]\n : undefined,\n ),\n composedExtensionContracts: context.composedExtensionContracts,\n ...ifDefined(\n 'composedExtensionPackRefs',\n options.composedExtensionPackRefs?.length\n ? options.composedExtensionPackRefs\n : undefined,\n ),\n controlMutationDefaults: context.controlMutationDefaults,\n ...ifDefined('createNamespace', options.createNamespace),\n });\n if (!interpreted.ok) {\n return interpreted;\n }\n\n return ok(\n applySpecifierDefaultControlPolicy(interpreted.value, options.defaultControlPolicy),\n );\n },\n },\n output: options.output ?? defaultOutputFromSchemaPath(schemaPath),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,SAAS,4BAA4B,YAA4B;CAC/D,MAAM,MAAM,QAAQ,UAAU;CAC9B,IAAI,IAAI,WAAW,GAAG,OAAO,GAAG,WAAW;CAC3C,MAAM,OAAO,WAAW,MAAM,GAAG,CAAC,IAAI,MAAM;CAK5C,IAAI,SAAS,IAAI,MAAM,UACrB,OAAO,GAAG,KAAK,MAAM,GAAG,EAAgB,EAAE;CAE5C,OAAO,GAAG,KAAK;AACjB;AAEA,SAAS,yBACP,uBACA,aACuC;CACvC,MAAM,yBAAS,IAAI,IAA8B;CACjD,KAAK,MAAM,CAAC,UAAU,YAAY,uBAAuB;EACvD,MAAM,aAAa,YAAY,eAAe,OAAO,CAAC,GAAG;EACzD,IAAI,eAAe,KAAA,GAAW;EAC9B,OAAO,IAAI,UAAU;GAAE;GAAS;EAAW,CAAC;CAC9C;CACA,OAAO;AACT;AAEA,SAAgB,eAAe,YAAoB,SAAgD;CACjG,OAAO;EACL,QAAQ;GACN,QAAQ,CAAC,UAAU;GACnB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,sBAAsB,QAAQ;IACrC,IAAI,uBAAuB,KAAA,GACzB,MAAM,IAAI,MACR,kIACF;IAEF,IAAI;IACJ,IAAI;KACF,SAAS,MAAM,SAAS,oBAAoB,OAAO;IACrD,SAAS,OAAO;KACd,MAAM,UAAU,OAAO,KAAK;KAC5B,OAAO,MAAM;MACX,SAAS,oCAAoC,WAAW;MACxD,aAAa,CACX;OACE,MAAM;OACN;OACA,UAAU;MACZ,CACF;MACA,MAAM;OAAE;OAAY;OAAoB,OAAO;MAAQ;KACzD,CAAC;IACH;IAEA,MAAM,WAAW,iBAAiB;KAChC;KACA,UAAU;
|
|
1
|
+
{"version":3,"file":"provider.mjs","names":[],"sources":["../src/provider.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { ContractConfig } from '@prisma-next/config/config-types';\nimport { applySpecifierDefaultControlPolicy } from '@prisma-next/contract/apply-specifier-default-control-policy';\nimport type { ControlPolicy } from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';\nimport type { Namespace } from '@prisma-next/framework-components/ir';\nimport { parsePslDocument } from '@prisma-next/psl-parser';\nimport type { SqlNamespaceTablesInput } from '@prisma-next/sql-contract/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { basename, extname } from 'pathe';\nimport { interpretPslDocumentToSqlContract } from './interpreter';\nimport type { ColumnDescriptor } from './psl-column-resolution';\n\nexport interface PrismaContractOptions {\n readonly output?: string;\n readonly target: TargetPackRef<'sql', string>;\n readonly composedExtensionPackRefs?: readonly ExtensionPackRef<'sql', string>[];\n readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;\n readonly defaultControlPolicy?: ControlPolicy;\n}\n\n/**\n * Derives the emit output path from the schema input path so artefacts land\n * colocated with the source (e.g. `src/contract/schema.prisma` →\n * `src/contract/contract.json`). The provider owns this because it is the\n * only layer that knows the input path; the upstream `normalizeContractConfig`\n * default is a last-resort fallback for providers that don't carry one.\n */\nfunction defaultOutputFromSchemaPath(schemaPath: string): string {\n const ext = extname(schemaPath);\n if (ext.length === 0) return `${schemaPath}.json`;\n const base = schemaPath.slice(0, -ext.length);\n // PSL schemas commonly use `schema.prisma`; the emitted JSON is called\n // `contract.json` to mirror the rest of the toolchain, not `schema.json`.\n // Match only the exact basename `schema` so files like `my-schema.prisma`\n // are not silently rewritten to `my-contract.json`.\n if (basename(base) === 'schema') {\n return `${base.slice(0, -'schema'.length)}contract.json`;\n }\n return `${base}.json`;\n}\n\nfunction buildColumnDescriptorMap(\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n codecLookup: CodecLookup,\n): ReadonlyMap<string, ColumnDescriptor> {\n const result = new Map<string, ColumnDescriptor>();\n for (const [typeName, codecId] of scalarTypeDescriptors) {\n const nativeType = codecLookup.targetTypesFor(codecId)?.[0];\n if (nativeType === undefined) continue;\n result.set(typeName, { codecId, nativeType });\n }\n return result;\n}\n\nexport function prismaContract(schemaPath: string, options: PrismaContractOptions): ContractConfig {\n return {\n source: {\n inputs: [schemaPath],\n load: async (context) => {\n const [absoluteSchemaPath] = context.resolvedInputs;\n if (absoluteSchemaPath === undefined) {\n throw new Error(\n 'prismaContract: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.',\n );\n }\n let schema: string;\n try {\n schema = await readFile(absoluteSchemaPath, 'utf-8');\n } catch (error) {\n const message = String(error);\n return notOk({\n summary: `Failed to read Prisma schema at \"${schemaPath}\"`,\n diagnostics: [\n {\n code: 'PSL_SCHEMA_READ_FAILED',\n message,\n sourceId: schemaPath,\n },\n ],\n meta: { schemaPath, absoluteSchemaPath, cause: message },\n });\n }\n\n const document = parsePslDocument({\n schema,\n sourceId: schemaPath,\n pslBlockDescriptors: context.authoringContributions.pslBlockDescriptors,\n });\n\n const scalarTypeDescriptors = buildColumnDescriptorMap(\n context.scalarTypeDescriptors,\n context.codecLookup,\n );\n\n const interpreted = interpretPslDocumentToSqlContract({\n document,\n target: options.target,\n authoringContributions: context.authoringContributions,\n scalarTypeDescriptors,\n ...ifDefined(\n 'composedExtensionPacks',\n context.composedExtensionPacks.length > 0\n ? [...context.composedExtensionPacks]\n : undefined,\n ),\n composedExtensionContracts: context.composedExtensionContracts,\n ...ifDefined(\n 'composedExtensionPackRefs',\n options.composedExtensionPackRefs?.length\n ? options.composedExtensionPackRefs\n : undefined,\n ),\n controlMutationDefaults: context.controlMutationDefaults,\n ...ifDefined('createNamespace', options.createNamespace),\n codecLookup: context.codecLookup,\n });\n if (!interpreted.ok) {\n return interpreted;\n }\n\n return ok(\n applySpecifierDefaultControlPolicy(interpreted.value, options.defaultControlPolicy),\n );\n },\n },\n output: options.output ?? defaultOutputFromSchemaPath(schemaPath),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,SAAS,4BAA4B,YAA4B;CAC/D,MAAM,MAAM,QAAQ,UAAU;CAC9B,IAAI,IAAI,WAAW,GAAG,OAAO,GAAG,WAAW;CAC3C,MAAM,OAAO,WAAW,MAAM,GAAG,CAAC,IAAI,MAAM;CAK5C,IAAI,SAAS,IAAI,MAAM,UACrB,OAAO,GAAG,KAAK,MAAM,GAAG,EAAgB,EAAE;CAE5C,OAAO,GAAG,KAAK;AACjB;AAEA,SAAS,yBACP,uBACA,aACuC;CACvC,MAAM,yBAAS,IAAI,IAA8B;CACjD,KAAK,MAAM,CAAC,UAAU,YAAY,uBAAuB;EACvD,MAAM,aAAa,YAAY,eAAe,OAAO,CAAC,GAAG;EACzD,IAAI,eAAe,KAAA,GAAW;EAC9B,OAAO,IAAI,UAAU;GAAE;GAAS;EAAW,CAAC;CAC9C;CACA,OAAO;AACT;AAEA,SAAgB,eAAe,YAAoB,SAAgD;CACjG,OAAO;EACL,QAAQ;GACN,QAAQ,CAAC,UAAU;GACnB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,sBAAsB,QAAQ;IACrC,IAAI,uBAAuB,KAAA,GACzB,MAAM,IAAI,MACR,kIACF;IAEF,IAAI;IACJ,IAAI;KACF,SAAS,MAAM,SAAS,oBAAoB,OAAO;IACrD,SAAS,OAAO;KACd,MAAM,UAAU,OAAO,KAAK;KAC5B,OAAO,MAAM;MACX,SAAS,oCAAoC,WAAW;MACxD,aAAa,CACX;OACE,MAAM;OACN;OACA,UAAU;MACZ,CACF;MACA,MAAM;OAAE;OAAY;OAAoB,OAAO;MAAQ;KACzD,CAAC;IACH;IAEA,MAAM,WAAW,iBAAiB;KAChC;KACA,UAAU;KACV,qBAAqB,QAAQ,uBAAuB;IACtD,CAAC;IAED,MAAM,wBAAwB,yBAC5B,QAAQ,uBACR,QAAQ,WACV;IAEA,MAAM,cAAc,kCAAkC;KACpD;KACA,QAAQ,QAAQ;KAChB,wBAAwB,QAAQ;KAChC;KACA,GAAG,UACD,0BACA,QAAQ,uBAAuB,SAAS,IACpC,CAAC,GAAG,QAAQ,sBAAsB,IAClC,KAAA,CACN;KACA,4BAA4B,QAAQ;KACpC,GAAG,UACD,6BACA,QAAQ,2BAA2B,SAC/B,QAAQ,4BACR,KAAA,CACN;KACA,yBAAyB,QAAQ;KACjC,GAAG,UAAU,mBAAmB,QAAQ,eAAe;KACvD,aAAa,QAAQ;IACvB,CAAC;IACD,IAAI,CAAC,YAAY,IACf,OAAO;IAGT,OAAO,GACL,mCAAmC,YAAY,OAAO,QAAQ,oBAAoB,CACpF;GACF;EACF;EACA,QAAQ,QAAQ,UAAU,4BAA4B,UAAU;CAClE;AACF"}
|
package/package.json
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-contract-psl",
|
|
3
|
-
"version": "0.13.0-dev.
|
|
3
|
+
"version": "0.13.0-dev.40",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "PSL-to-SQL ContractIR interpreter for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/config": "0.13.0-dev.
|
|
10
|
-
"@prisma-next/contract": "0.13.0-dev.
|
|
11
|
-
"@prisma-next/framework-components": "0.13.0-dev.
|
|
12
|
-
"@prisma-next/psl-parser": "0.13.0-dev.
|
|
13
|
-
"@prisma-next/sql-contract": "0.13.0-dev.
|
|
14
|
-
"@prisma-next/sql-contract-ts": "0.13.0-dev.
|
|
15
|
-
"@prisma-next/utils": "0.13.0-dev.
|
|
9
|
+
"@prisma-next/config": "0.13.0-dev.40",
|
|
10
|
+
"@prisma-next/contract": "0.13.0-dev.40",
|
|
11
|
+
"@prisma-next/framework-components": "0.13.0-dev.40",
|
|
12
|
+
"@prisma-next/psl-parser": "0.13.0-dev.40",
|
|
13
|
+
"@prisma-next/sql-contract": "0.13.0-dev.40",
|
|
14
|
+
"@prisma-next/sql-contract-ts": "0.13.0-dev.40",
|
|
15
|
+
"@prisma-next/utils": "0.13.0-dev.40",
|
|
16
16
|
"pathe": "^2.0.3"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@prisma-next/contract-authoring": "0.13.0-dev.
|
|
20
|
-
"@prisma-next/test-utils": "0.13.0-dev.
|
|
21
|
-
"@prisma-next/tsconfig": "0.13.0-dev.
|
|
22
|
-
"@prisma-next/tsdown": "0.13.0-dev.
|
|
19
|
+
"@prisma-next/contract-authoring": "0.13.0-dev.40",
|
|
20
|
+
"@prisma-next/test-utils": "0.13.0-dev.40",
|
|
21
|
+
"@prisma-next/tsconfig": "0.13.0-dev.40",
|
|
22
|
+
"@prisma-next/tsdown": "0.13.0-dev.40",
|
|
23
23
|
"arktype": "^2.2.0",
|
|
24
24
|
"tsdown": "0.22.1",
|
|
25
25
|
"typescript": "5.9.3",
|
package/src/interpreter.ts
CHANGED
|
@@ -14,9 +14,9 @@ import { crossRef } from '@prisma-next/contract/types';
|
|
|
14
14
|
import type {
|
|
15
15
|
AuthoringContributions,
|
|
16
16
|
AuthoringEntityContext,
|
|
17
|
-
AuthoringEntityTypeDescriptor,
|
|
18
17
|
} from '@prisma-next/framework-components/authoring';
|
|
19
18
|
import { instantiateAuthoringEntityType } from '@prisma-next/framework-components/authoring';
|
|
19
|
+
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
20
20
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
|
|
21
21
|
import type {
|
|
22
22
|
ControlMutationDefaultRegistry,
|
|
@@ -24,25 +24,25 @@ import type {
|
|
|
24
24
|
MutationDefaultGeneratorDescriptor,
|
|
25
25
|
} from '@prisma-next/framework-components/control';
|
|
26
26
|
import type { Namespace } from '@prisma-next/framework-components/ir';
|
|
27
|
+
import { namespacePslExtensionBlocks } from '@prisma-next/framework-components/psl-ast';
|
|
27
28
|
import type {
|
|
28
29
|
ParsePslDocumentResult,
|
|
29
30
|
PslAttribute,
|
|
30
31
|
PslCompositeType,
|
|
31
|
-
|
|
32
|
+
PslExtensionBlock,
|
|
32
33
|
PslField,
|
|
33
34
|
PslModel,
|
|
34
35
|
PslNamedTypeDeclaration,
|
|
35
36
|
PslNamespace,
|
|
36
37
|
} from '@prisma-next/psl-parser';
|
|
37
|
-
import {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
type SqlNamespaceTablesInput,
|
|
42
|
-
type StorageTypeInstance,
|
|
38
|
+
import type {
|
|
39
|
+
SqlModelStorage,
|
|
40
|
+
SqlNamespaceTablesInput,
|
|
41
|
+
StorageTypeInstance,
|
|
43
42
|
} from '@prisma-next/sql-contract/types';
|
|
44
43
|
import {
|
|
45
44
|
buildSqlContractFromDefinition,
|
|
45
|
+
type EnumTypeHandle,
|
|
46
46
|
type FieldNode,
|
|
47
47
|
type ForeignKeyNode,
|
|
48
48
|
type IndexNode,
|
|
@@ -63,7 +63,6 @@ import {
|
|
|
63
63
|
parseAttributeFieldList,
|
|
64
64
|
parseConstraintMapArgument,
|
|
65
65
|
parseControlPolicyAttribute,
|
|
66
|
-
parseMapName,
|
|
67
66
|
parseObjectLiteralStringMap,
|
|
68
67
|
parseQuotedStringLiteral,
|
|
69
68
|
} from './psl-attribute-parsing';
|
|
@@ -124,6 +123,7 @@ export interface InterpretPslDocumentToSqlContractInput {
|
|
|
124
123
|
* `SqlUnboundNamespace` singleton.
|
|
125
124
|
*/
|
|
126
125
|
readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
|
|
126
|
+
readonly codecLookup?: CodecLookup;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
function buildComposedExtensionPackRefs(
|
|
@@ -302,77 +302,56 @@ function validateNamespaceBlocksForSqlTarget(input: {
|
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
interface ProcessEnumDeclarationsInput {
|
|
305
|
-
readonly
|
|
305
|
+
readonly enumBlocks: readonly PslExtensionBlock[];
|
|
306
306
|
readonly sourceId: string;
|
|
307
|
-
readonly
|
|
307
|
+
readonly authoringContributions: AuthoringContributions | undefined;
|
|
308
308
|
readonly entityContext: AuthoringEntityContext;
|
|
309
309
|
readonly diagnostics: ContractSourceDiagnostic[];
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
function processEnumDeclarations(input: ProcessEnumDeclarationsInput): {
|
|
313
|
-
readonly
|
|
313
|
+
readonly enumHandles: Record<string, EnumTypeHandle>;
|
|
314
314
|
readonly enumTypeDescriptors: Map<string, ColumnDescriptor>;
|
|
315
315
|
} {
|
|
316
|
-
const
|
|
316
|
+
const enumHandles: Record<string, EnumTypeHandle> = {};
|
|
317
317
|
const enumTypeDescriptors = new Map<string, ColumnDescriptor>();
|
|
318
318
|
|
|
319
|
-
if (input.
|
|
320
|
-
return {
|
|
319
|
+
if (input.enumBlocks.length === 0) {
|
|
320
|
+
return { enumHandles, enumTypeDescriptors };
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
// Postgres target pack does so today via
|
|
327
|
-
// `authoring.entityTypes.enum`). Without the contribution we
|
|
328
|
-
// surface a diagnostic per declaration rather than silently
|
|
329
|
-
// swallowing the syntax.
|
|
330
|
-
for (const enumDeclaration of input.enums) {
|
|
323
|
+
const enumDescriptor = getAuthoringEntity(input.authoringContributions, ['enum']);
|
|
324
|
+
if (!enumDescriptor) {
|
|
325
|
+
for (const decl of input.enumBlocks) {
|
|
331
326
|
input.diagnostics.push({
|
|
332
|
-
code: '
|
|
333
|
-
message: `
|
|
327
|
+
code: 'PSL_ENUM_MISSING_FACTORY',
|
|
328
|
+
message: `enum "${decl.name}" requires an "enum" entityType factory in the active authoring contributions`,
|
|
334
329
|
sourceId: input.sourceId,
|
|
335
|
-
span:
|
|
330
|
+
span: decl.span,
|
|
336
331
|
});
|
|
337
332
|
}
|
|
338
|
-
return {
|
|
333
|
+
return { enumHandles, enumTypeDescriptors };
|
|
339
334
|
}
|
|
340
335
|
|
|
341
|
-
for (const
|
|
342
|
-
const
|
|
343
|
-
attribute: getAttribute(enumDeclaration.attributes, 'map'),
|
|
344
|
-
defaultValue: enumDeclaration.name,
|
|
345
|
-
sourceId: input.sourceId,
|
|
346
|
-
diagnostics: input.diagnostics,
|
|
347
|
-
entityLabel: `Enum "${enumDeclaration.name}"`,
|
|
348
|
-
span: enumDeclaration.span,
|
|
349
|
-
});
|
|
350
|
-
const values = enumDeclaration.values.map((value) => value.name);
|
|
351
|
-
const constructed = instantiateAuthoringEntityType(
|
|
336
|
+
for (const decl of input.enumBlocks) {
|
|
337
|
+
const handle = instantiateAuthoringEntityType(
|
|
352
338
|
'enum',
|
|
353
|
-
|
|
354
|
-
[
|
|
339
|
+
enumDescriptor,
|
|
340
|
+
[decl],
|
|
355
341
|
input.entityContext,
|
|
356
342
|
);
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
const descriptor: ColumnDescriptor = {
|
|
367
|
-
codecId: constructed.codecId,
|
|
368
|
-
nativeType: constructed.nativeType,
|
|
369
|
-
typeRef: enumDeclaration.name,
|
|
370
|
-
};
|
|
371
|
-
enumTypeDescriptors.set(enumDeclaration.name, descriptor);
|
|
372
|
-
storageTypes[enumDeclaration.name] = constructed;
|
|
343
|
+
|
|
344
|
+
if (handle === undefined || handle === null) continue;
|
|
345
|
+
|
|
346
|
+
const enumHandle = blindCast<EnumTypeHandle, 'enum factory returns EnumTypeHandle'>(handle);
|
|
347
|
+
enumHandles[decl.name] = enumHandle;
|
|
348
|
+
enumTypeDescriptors.set(decl.name, {
|
|
349
|
+
codecId: enumHandle.codecId,
|
|
350
|
+
nativeType: enumHandle.nativeType,
|
|
351
|
+
});
|
|
373
352
|
}
|
|
374
353
|
|
|
375
|
-
return {
|
|
354
|
+
return { enumHandles, enumTypeDescriptors };
|
|
376
355
|
}
|
|
377
356
|
|
|
378
357
|
interface ResolveNamedTypeDeclarationsInput {
|
|
@@ -451,10 +430,10 @@ function validateNamedTypeAttributes(input: {
|
|
|
451
430
|
}
|
|
452
431
|
|
|
453
432
|
function resolveNamedTypeDeclarations(input: ResolveNamedTypeDeclarationsInput): {
|
|
454
|
-
readonly storageTypes: Record<string, StorageTypeInstance
|
|
433
|
+
readonly storageTypes: Record<string, StorageTypeInstance>;
|
|
455
434
|
readonly namedTypeDescriptors: Map<string, ColumnDescriptor>;
|
|
456
435
|
} {
|
|
457
|
-
const storageTypes: Record<string, StorageTypeInstance
|
|
436
|
+
const storageTypes: Record<string, StorageTypeInstance> = {};
|
|
458
437
|
const namedTypeDescriptors = new Map<string, ColumnDescriptor>();
|
|
459
438
|
|
|
460
439
|
for (const declaration of input.declarations) {
|
|
@@ -619,6 +598,7 @@ interface BuildModelNodeInput {
|
|
|
619
598
|
readonly diagnostics: ContractSourceDiagnostic[];
|
|
620
599
|
/** Resolved namespace id keyed by model name — used to stamp the target namespace on FKs. */
|
|
621
600
|
readonly modelNamespaceIds: ReadonlyMap<string, string>;
|
|
601
|
+
readonly enumHandles?: ReadonlyMap<string, EnumTypeHandle>;
|
|
622
602
|
}
|
|
623
603
|
|
|
624
604
|
interface BuildModelNodeResult {
|
|
@@ -650,6 +630,7 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
650
630
|
diagnostics,
|
|
651
631
|
sourceId,
|
|
652
632
|
scalarTypeDescriptors: input.scalarTypeDescriptors,
|
|
633
|
+
...ifDefined('enumHandles', input.enumHandles),
|
|
653
634
|
});
|
|
654
635
|
|
|
655
636
|
const inlineIdFields = resolvedFields.filter((field) => field.isId);
|
|
@@ -1320,14 +1301,18 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
1320
1301
|
modelNode: {
|
|
1321
1302
|
modelName: model.name,
|
|
1322
1303
|
tableName,
|
|
1323
|
-
fields: resolvedFields.map((resolvedField) =>
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1304
|
+
fields: resolvedFields.map((resolvedField) => {
|
|
1305
|
+
const enumHandle = input.enumHandles?.get(resolvedField.field.typeName);
|
|
1306
|
+
return {
|
|
1307
|
+
fieldName: resolvedField.field.name,
|
|
1308
|
+
columnName: resolvedField.columnName,
|
|
1309
|
+
descriptor: resolvedField.descriptor,
|
|
1310
|
+
nullable: resolvedField.field.optional,
|
|
1311
|
+
...ifDefined('default', resolvedField.defaultValue),
|
|
1312
|
+
...ifDefined('executionDefaults', resolvedField.executionDefaults),
|
|
1313
|
+
...ifDefined('enumTypeHandle', enumHandle),
|
|
1314
|
+
};
|
|
1315
|
+
}),
|
|
1331
1316
|
...ifDefined('id', primaryKey),
|
|
1332
1317
|
...(uniqueConstraints.length > 0 ? { uniques: uniqueConstraints } : {}),
|
|
1333
1318
|
...(indexNodes.length > 0 ? { indexes: indexNodes } : {}),
|
|
@@ -1924,33 +1909,6 @@ export function interpretPslDocumentToSqlContract(
|
|
|
1924
1909
|
}
|
|
1925
1910
|
}
|
|
1926
1911
|
const defaultNamespaceId = input.target.defaultNamespaceId;
|
|
1927
|
-
// Top-level enums (the __unspecified__ bucket) route to `storageTypes`;
|
|
1928
|
-
// enums inside a named namespace block route to `namespaceTypes[nsId]`.
|
|
1929
|
-
const topLevelEnums = input.document.ast.namespaces
|
|
1930
|
-
.filter((ns) => ns.name === UNSPECIFIED_PSL_NAMESPACE_NAME)
|
|
1931
|
-
.flatMap((ns) => ns.enums);
|
|
1932
|
-
const namedNamespaceEnumsByNsId = new Map<string, readonly PslEnum[]>();
|
|
1933
|
-
for (const ns of input.document.ast.namespaces) {
|
|
1934
|
-
if (ns.name === UNSPECIFIED_PSL_NAMESPACE_NAME || ns.enums.length === 0) {
|
|
1935
|
-
continue;
|
|
1936
|
-
}
|
|
1937
|
-
const resolvedId = resolveNamespaceIdForSqlTarget({
|
|
1938
|
-
bucketName: ns.name,
|
|
1939
|
-
targetId: input.target.targetId,
|
|
1940
|
-
});
|
|
1941
|
-
if (resolvedId === undefined) {
|
|
1942
|
-
continue;
|
|
1943
|
-
}
|
|
1944
|
-
// Read-then-merge so that any future change to the PSL parser (or to
|
|
1945
|
-
// `resolveNamespaceIdForSqlTarget`) that produces two AST entries
|
|
1946
|
-
// resolving to the same `resolvedId` would accumulate their enums
|
|
1947
|
-
// rather than silently dropping the earlier set. Today the parser
|
|
1948
|
-
// already merges duplicate `namespace <name> { … }` blocks into a
|
|
1949
|
-
// single AST entry per name, so this loop sees one `ns` per
|
|
1950
|
-
// resolvedId and the merge degrades to a plain set.
|
|
1951
|
-
const existing = namedNamespaceEnumsByNsId.get(resolvedId) ?? [];
|
|
1952
|
-
namedNamespaceEnumsByNsId.set(resolvedId, [...existing, ...ns.enums]);
|
|
1953
|
-
}
|
|
1954
1912
|
|
|
1955
1913
|
const compositeTypes = input.document.ast.namespaces.flatMap((ns) => ns.compositeTypes);
|
|
1956
1914
|
const modelNames = new Set(models.map((model) => model.name));
|
|
@@ -1966,45 +1924,48 @@ export function interpretPslDocumentToSqlContract(
|
|
|
1966
1924
|
generatorDescriptorById.set(descriptor.id, descriptor);
|
|
1967
1925
|
}
|
|
1968
1926
|
|
|
1969
|
-
const
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1927
|
+
const topLevelEnums = input.document.ast.namespaces
|
|
1928
|
+
.filter((ns) => ns.name === UNSPECIFIED_PSL_NAMESPACE_NAME)
|
|
1929
|
+
.flatMap((ns) => namespacePslExtensionBlocks(ns).filter((b) => b.kind === 'enum'));
|
|
1930
|
+
for (const ns of input.document.ast.namespaces) {
|
|
1931
|
+
if (ns.name === UNSPECIFIED_PSL_NAMESPACE_NAME) continue;
|
|
1932
|
+
const nsEnums = namespacePslExtensionBlocks(ns).filter((b) => b.kind === 'enum');
|
|
1933
|
+
if (nsEnums.length === 0) continue;
|
|
1934
|
+
for (const decl of nsEnums) {
|
|
1935
|
+
diagnostics.push({
|
|
1936
|
+
code: 'PSL_ENUM_NAMESPACE_NOT_SUPPORTED',
|
|
1937
|
+
message: `enum "${decl.name}" inside namespace "${ns.name}" is not supported; declare enum at the top level`,
|
|
1938
|
+
sourceId,
|
|
1939
|
+
span: decl.span,
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1974
1943
|
|
|
1975
1944
|
const enumResult = processEnumDeclarations({
|
|
1976
|
-
|
|
1945
|
+
enumBlocks: topLevelEnums,
|
|
1977
1946
|
sourceId,
|
|
1978
|
-
|
|
1979
|
-
entityContext:
|
|
1947
|
+
authoringContributions: input.authoringContributions,
|
|
1948
|
+
entityContext: {
|
|
1949
|
+
family: input.target.familyId,
|
|
1950
|
+
target: input.target.targetId,
|
|
1951
|
+
...ifDefined('codecLookup', input.codecLookup),
|
|
1952
|
+
sourceId,
|
|
1953
|
+
diagnostics: {
|
|
1954
|
+
push: (d) => {
|
|
1955
|
+
diagnostics.push(
|
|
1956
|
+
blindCast<ContractSourceDiagnostic, 'sink diagnostics are span-compatible'>(d),
|
|
1957
|
+
);
|
|
1958
|
+
},
|
|
1959
|
+
},
|
|
1960
|
+
},
|
|
1980
1961
|
diagnostics,
|
|
1981
1962
|
});
|
|
1982
1963
|
|
|
1983
|
-
// Process enums declared in named namespace blocks and collect them into
|
|
1984
|
-
// `namespaceTypes` keyed by the resolved namespace id.
|
|
1985
1964
|
const allEnumTypeDescriptors = new Map(enumResult.enumTypeDescriptors);
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
sourceId,
|
|
1991
|
-
enumEntityDescriptor,
|
|
1992
|
-
entityContext: enumEntityContext,
|
|
1993
|
-
diagnostics,
|
|
1994
|
-
});
|
|
1995
|
-
for (const [name, descriptor] of nsEnumResult.enumTypeDescriptors) {
|
|
1996
|
-
allEnumTypeDescriptors.set(name, descriptor);
|
|
1997
|
-
}
|
|
1998
|
-
const nsEntries: Record<string, PostgresEnumStorageEntry> = {};
|
|
1999
|
-
for (const [name, entry] of Object.entries(nsEnumResult.storageTypes)) {
|
|
2000
|
-
if (isPostgresEnumStorageEntry(entry)) {
|
|
2001
|
-
nsEntries[name] = entry;
|
|
2002
|
-
}
|
|
2003
|
-
}
|
|
2004
|
-
if (Object.keys(nsEntries).length > 0) {
|
|
2005
|
-
namespaceEnumStorageTypes[nsId] = nsEntries;
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
1965
|
+
|
|
1966
|
+
const validEnumHandles: Record<string, EnumTypeHandle> = { ...enumResult.enumHandles };
|
|
1967
|
+
|
|
1968
|
+
const enumHandlesByName = new Map(Object.entries(validEnumHandles));
|
|
2008
1969
|
|
|
2009
1970
|
const namedTypeResult = resolveNamedTypeDeclarations({
|
|
2010
1971
|
declarations: input.document.ast.types?.declarations ?? [],
|
|
@@ -2018,7 +1979,7 @@ export function interpretPslDocumentToSqlContract(
|
|
|
2018
1979
|
diagnostics,
|
|
2019
1980
|
});
|
|
2020
1981
|
|
|
2021
|
-
const storageTypes = { ...
|
|
1982
|
+
const storageTypes = { ...namedTypeResult.storageTypes };
|
|
2022
1983
|
|
|
2023
1984
|
const modelMappingsByCoordinate = buildModelMappings(
|
|
2024
1985
|
modelEntries,
|
|
@@ -2068,6 +2029,7 @@ export function interpretPslDocumentToSqlContract(
|
|
|
2068
2029
|
sourceId,
|
|
2069
2030
|
diagnostics,
|
|
2070
2031
|
modelNamespaceIds,
|
|
2032
|
+
...(enumHandlesByName.size > 0 ? { enumHandles: enumHandlesByName } : {}),
|
|
2071
2033
|
});
|
|
2072
2034
|
modelNodes.push(
|
|
2073
2035
|
namespaceId !== undefined ? { ...result.modelNode, namespaceId } : result.modelNode,
|
|
@@ -2159,9 +2121,7 @@ export function interpretPslDocumentToSqlContract(
|
|
|
2159
2121
|
),
|
|
2160
2122
|
),
|
|
2161
2123
|
...(Object.keys(storageTypes).length > 0 ? { storageTypes } : {}),
|
|
2162
|
-
...(Object.keys(
|
|
2163
|
-
? { namespaceTypes: namespaceEnumStorageTypes }
|
|
2164
|
-
: {}),
|
|
2124
|
+
...(Object.keys(validEnumHandles).length > 0 ? { enums: validEnumHandles } : {}),
|
|
2165
2125
|
...ifDefined('createNamespace', input.createNamespace),
|
|
2166
2126
|
models: stiColumnModelNodes.map((model) => ({
|
|
2167
2127
|
...model,
|
|
@@ -2233,6 +2193,7 @@ export function interpretPslDocumentToSqlContract(
|
|
|
2233
2193
|
patchedModels[modelCoordinateKey(namespaceId, modelName)] ?? model,
|
|
2234
2194
|
]),
|
|
2235
2195
|
),
|
|
2196
|
+
...(namespaceSlice.enum !== undefined ? { enum: namespaceSlice.enum } : {}),
|
|
2236
2197
|
...(namespaceSlice.valueObjects !== undefined
|
|
2237
2198
|
? { valueObjects: namespaceSlice.valueObjects }
|
|
2238
2199
|
: {}),
|
package/src/provider.ts
CHANGED
|
@@ -87,6 +87,7 @@ export function prismaContract(schemaPath: string, options: PrismaContractOption
|
|
|
87
87
|
const document = parsePslDocument({
|
|
88
88
|
schema,
|
|
89
89
|
sourceId: schemaPath,
|
|
90
|
+
pslBlockDescriptors: context.authoringContributions.pslBlockDescriptors,
|
|
90
91
|
});
|
|
91
92
|
|
|
92
93
|
const scalarTypeDescriptors = buildColumnDescriptorMap(
|
|
@@ -114,6 +115,7 @@ export function prismaContract(schemaPath: string, options: PrismaContractOption
|
|
|
114
115
|
),
|
|
115
116
|
controlMutationDefaults: context.controlMutationDefaults,
|
|
116
117
|
...ifDefined('createNamespace', options.createNamespace),
|
|
118
|
+
codecLookup: context.codecLookup,
|
|
117
119
|
});
|
|
118
120
|
if (!interpreted.ok) {
|
|
119
121
|
return interpreted;
|
|
@@ -550,7 +550,7 @@ export const NATIVE_TYPE_SPECS: Readonly<Record<string, NativeTypeSpec>> = {
|
|
|
550
550
|
codecId: 'sql/char@1',
|
|
551
551
|
nativeType: 'character',
|
|
552
552
|
},
|
|
553
|
-
'db.Uuid': { args: 'noArgs', baseType: 'String', codecId:
|
|
553
|
+
'db.Uuid': { args: 'noArgs', baseType: 'String', codecId: 'pg/uuid@1', nativeType: 'uuid' },
|
|
554
554
|
'db.SmallInt': { args: 'noArgs', baseType: 'Int', codecId: 'pg/int2@1', nativeType: 'int2' },
|
|
555
555
|
'db.Real': { args: 'noArgs', baseType: 'Float', codecId: 'pg/float4@1', nativeType: 'float4' },
|
|
556
556
|
'db.Numeric': {
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import type { ContractSourceDiagnostic } from '@prisma-next/config/config-types';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ColumnDefault,
|
|
4
|
+
ColumnDefaultLiteralInputValue,
|
|
5
|
+
ExecutionMutationDefaultPhases,
|
|
6
|
+
} from '@prisma-next/contract/types';
|
|
3
7
|
import type { AuthoringContributions } from '@prisma-next/framework-components/authoring';
|
|
4
8
|
import type {
|
|
5
9
|
ControlMutationDefaultRegistry,
|
|
6
10
|
MutationDefaultGeneratorDescriptor,
|
|
7
11
|
} from '@prisma-next/framework-components/control';
|
|
8
12
|
import type { PslAttribute, PslField, PslModel } from '@prisma-next/psl-parser';
|
|
13
|
+
import type { EnumTypeHandle } from '@prisma-next/sql-contract-ts/contract-builder';
|
|
14
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
9
15
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
10
16
|
import {
|
|
11
17
|
getAttribute,
|
|
18
|
+
getPositionalArgumentEntry,
|
|
12
19
|
lowerFirst,
|
|
13
20
|
parseConstraintMapArgument,
|
|
14
21
|
parseMapName,
|
|
@@ -21,6 +28,61 @@ import {
|
|
|
21
28
|
resolveFieldTypeDescriptor,
|
|
22
29
|
} from './psl-column-resolution';
|
|
23
30
|
|
|
31
|
+
type LoweredFieldDefault = {
|
|
32
|
+
readonly defaultValue?: ColumnDefault;
|
|
33
|
+
readonly executionDefaults?: ExecutionMutationDefaultPhases;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function lowerEnumDefaultForField(input: {
|
|
37
|
+
readonly modelName: string;
|
|
38
|
+
readonly fieldName: string;
|
|
39
|
+
readonly defaultAttribute: PslAttribute;
|
|
40
|
+
readonly enumHandle: EnumTypeHandle;
|
|
41
|
+
readonly sourceId: string;
|
|
42
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
43
|
+
}): LoweredFieldDefault {
|
|
44
|
+
const expressionEntry = getPositionalArgumentEntry(input.defaultAttribute);
|
|
45
|
+
if (!expressionEntry) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const raw = expressionEntry.value.trim();
|
|
50
|
+
const isQuotedString = /^(['"]).*\1$/.test(raw);
|
|
51
|
+
const isFunctionCall = raw.includes('(') && raw.endsWith(')');
|
|
52
|
+
|
|
53
|
+
if (isQuotedString || isFunctionCall) {
|
|
54
|
+
input.diagnostics.push({
|
|
55
|
+
code: 'PSL_ENUM_DEFAULT_MUST_BE_MEMBER_NAME',
|
|
56
|
+
message: `Field "${input.modelName}.${input.fieldName}" @default on an enum field must name a member (e.g. @default(Low)), not a raw value or function.`,
|
|
57
|
+
sourceId: input.sourceId,
|
|
58
|
+
span: input.defaultAttribute.span,
|
|
59
|
+
});
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const match = input.enumHandle.enumMembers.find((m) => m.name === raw);
|
|
64
|
+
if (!match) {
|
|
65
|
+
const validNames = input.enumHandle.enumMembers.map((m) => m.name).join(', ');
|
|
66
|
+
input.diagnostics.push({
|
|
67
|
+
code: 'PSL_ENUM_UNKNOWN_DEFAULT_MEMBER',
|
|
68
|
+
message: `Field "${input.modelName}.${input.fieldName}" @default(${raw}) does not name a member of ${input.enumHandle.enumName}. Valid members: ${validNames}.`,
|
|
69
|
+
sourceId: input.sourceId,
|
|
70
|
+
span: input.defaultAttribute.span,
|
|
71
|
+
});
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
defaultValue: {
|
|
77
|
+
kind: 'literal',
|
|
78
|
+
value: blindCast<
|
|
79
|
+
ColumnDefaultLiteralInputValue,
|
|
80
|
+
'enum member values are codec-validated JsonValue-compatible scalars'
|
|
81
|
+
>(match.value),
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
24
86
|
export type ResolvedField = {
|
|
25
87
|
readonly field: PslField;
|
|
26
88
|
readonly columnName: string;
|
|
@@ -76,6 +138,7 @@ export interface CollectResolvedFieldsInput {
|
|
|
76
138
|
readonly diagnostics: ContractSourceDiagnostic[];
|
|
77
139
|
readonly sourceId: string;
|
|
78
140
|
readonly scalarTypeDescriptors: ReadonlyMap<string, ColumnDescriptor>;
|
|
141
|
+
readonly enumHandles?: ReadonlyMap<string, EnumTypeHandle>;
|
|
79
142
|
}
|
|
80
143
|
|
|
81
144
|
const BUILTIN_FIELD_ATTRIBUTE_NAMES: ReadonlySet<string> = new Set([
|
|
@@ -95,7 +158,7 @@ const BUILTIN_FIELD_ATTRIBUTE_NAMES: ReadonlySet<string> = new Set([
|
|
|
95
158
|
* migrated (so they don't get told to do what they just did).
|
|
96
159
|
*
|
|
97
160
|
* Pairing the suppression predicate with the hint makes each entry
|
|
98
|
-
* self-contained: a future entry for, say, `@id` ↔ `id.
|
|
161
|
+
* self-contained: a future entry for, say, `@id` ↔ `id.uuidv7String()` cannot
|
|
99
162
|
* silently inherit the wrong predicate when added.
|
|
100
163
|
*/
|
|
101
164
|
interface RemovedAttributeRule {
|
|
@@ -225,6 +288,7 @@ export function collectResolvedFields(input: CollectResolvedFieldsInput): Resolv
|
|
|
225
288
|
diagnostics,
|
|
226
289
|
sourceId,
|
|
227
290
|
scalarTypeDescriptors,
|
|
291
|
+
enumHandles,
|
|
228
292
|
} = input;
|
|
229
293
|
const resolvedFields: ResolvedField[] = [];
|
|
230
294
|
|
|
@@ -350,17 +414,27 @@ export function collectResolvedFields(input: CollectResolvedFieldsInput): Resolv
|
|
|
350
414
|
});
|
|
351
415
|
continue;
|
|
352
416
|
}
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
417
|
+
const enumHandle = enumHandles?.get(field.typeName);
|
|
418
|
+
const loweredDefault: LoweredFieldDefault = defaultAttribute
|
|
419
|
+
? enumHandle
|
|
420
|
+
? lowerEnumDefaultForField({
|
|
421
|
+
modelName: model.name,
|
|
422
|
+
fieldName: field.name,
|
|
423
|
+
defaultAttribute,
|
|
424
|
+
enumHandle,
|
|
425
|
+
sourceId,
|
|
426
|
+
diagnostics,
|
|
427
|
+
})
|
|
428
|
+
: lowerDefaultForField({
|
|
429
|
+
modelName: model.name,
|
|
430
|
+
fieldName: field.name,
|
|
431
|
+
defaultAttribute,
|
|
432
|
+
columnDescriptor: descriptor,
|
|
433
|
+
generatorDescriptorById,
|
|
434
|
+
sourceId,
|
|
435
|
+
defaultFunctionRegistry,
|
|
436
|
+
diagnostics,
|
|
437
|
+
})
|
|
364
438
|
: {};
|
|
365
439
|
const loweredOnCreate = loweredDefault.executionDefaults?.onCreate;
|
|
366
440
|
if (field.optional && loweredOnCreate) {
|
|
@@ -374,7 +448,9 @@ export function collectResolvedFields(input: CollectResolvedFieldsInput): Resolv
|
|
|
374
448
|
});
|
|
375
449
|
continue;
|
|
376
450
|
}
|
|
377
|
-
|
|
451
|
+
const fieldUsesNamedType =
|
|
452
|
+
field.typeRef !== undefined || namedTypeDescriptors.has(field.typeName);
|
|
453
|
+
if (loweredOnCreate && !fieldUsesNamedType) {
|
|
378
454
|
const generatorDescriptor = generatorDescriptorById.get(loweredOnCreate.id);
|
|
379
455
|
const generatedDescriptor = generatorDescriptor?.resolveGeneratedColumnDescriptor?.({
|
|
380
456
|
generated: loweredOnCreate,
|