@prisma-next/sql-contract-psl 0.13.0-dev.16 → 0.13.0-dev.18
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 +2 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{interpreter-B_KtZusL.mjs → interpreter-CQdQo427.mjs} +137 -13
- package/dist/interpreter-CQdQo427.mjs.map +1 -0
- package/dist/provider.mjs +5 -3
- package/dist/provider.mjs.map +1 -1
- package/package.json +12 -12
- package/src/interpreter.ts +137 -8
- package/src/provider.ts +2 -0
- package/src/psl-field-resolution.ts +86 -12
- package/dist/interpreter-B_KtZusL.mjs.map +0 -1
package/dist/provider.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as interpretPslDocumentToSqlContract } from "./interpreter-
|
|
1
|
+
import { t as interpretPslDocumentToSqlContract } from "./interpreter-CQdQo427.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.18",
|
|
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.18",
|
|
10
|
+
"@prisma-next/contract": "0.13.0-dev.18",
|
|
11
|
+
"@prisma-next/framework-components": "0.13.0-dev.18",
|
|
12
|
+
"@prisma-next/psl-parser": "0.13.0-dev.18",
|
|
13
|
+
"@prisma-next/sql-contract": "0.13.0-dev.18",
|
|
14
|
+
"@prisma-next/sql-contract-ts": "0.13.0-dev.18",
|
|
15
|
+
"@prisma-next/utils": "0.13.0-dev.18",
|
|
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.18",
|
|
20
|
+
"@prisma-next/test-utils": "0.13.0-dev.18",
|
|
21
|
+
"@prisma-next/tsconfig": "0.13.0-dev.18",
|
|
22
|
+
"@prisma-next/tsdown": "0.13.0-dev.18",
|
|
23
23
|
"arktype": "^2.2.0",
|
|
24
24
|
"tsdown": "0.22.1",
|
|
25
25
|
"typescript": "5.9.3",
|
package/src/interpreter.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
AuthoringEntityTypeDescriptor,
|
|
18
18
|
} from '@prisma-next/framework-components/authoring';
|
|
19
19
|
import { instantiateAuthoringEntityType } from '@prisma-next/framework-components/authoring';
|
|
20
|
+
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
20
21
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
|
|
21
22
|
import type {
|
|
22
23
|
ControlMutationDefaultRegistry,
|
|
@@ -24,11 +25,13 @@ import type {
|
|
|
24
25
|
MutationDefaultGeneratorDescriptor,
|
|
25
26
|
} from '@prisma-next/framework-components/control';
|
|
26
27
|
import type { Namespace } from '@prisma-next/framework-components/ir';
|
|
28
|
+
import { namespacePslExtensionBlocks } from '@prisma-next/framework-components/psl-ast';
|
|
27
29
|
import type {
|
|
28
30
|
ParsePslDocumentResult,
|
|
29
31
|
PslAttribute,
|
|
30
32
|
PslCompositeType,
|
|
31
33
|
PslEnum,
|
|
34
|
+
PslExtensionBlock,
|
|
32
35
|
PslField,
|
|
33
36
|
PslModel,
|
|
34
37
|
PslNamedTypeDeclaration,
|
|
@@ -43,6 +46,7 @@ import {
|
|
|
43
46
|
} from '@prisma-next/sql-contract/types';
|
|
44
47
|
import {
|
|
45
48
|
buildSqlContractFromDefinition,
|
|
49
|
+
type EnumTypeHandle,
|
|
46
50
|
type FieldNode,
|
|
47
51
|
type ForeignKeyNode,
|
|
48
52
|
type IndexNode,
|
|
@@ -124,6 +128,7 @@ export interface InterpretPslDocumentToSqlContractInput {
|
|
|
124
128
|
* `SqlUnboundNamespace` singleton.
|
|
125
129
|
*/
|
|
126
130
|
readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
|
|
131
|
+
readonly codecLookup?: CodecLookup;
|
|
127
132
|
}
|
|
128
133
|
|
|
129
134
|
function buildComposedExtensionPackRefs(
|
|
@@ -375,6 +380,59 @@ function processEnumDeclarations(input: ProcessEnumDeclarationsInput): {
|
|
|
375
380
|
return { storageTypes, enumTypeDescriptors };
|
|
376
381
|
}
|
|
377
382
|
|
|
383
|
+
interface ProcessEnum2DeclarationsInput {
|
|
384
|
+
readonly enum2Blocks: readonly PslExtensionBlock[];
|
|
385
|
+
readonly sourceId: string;
|
|
386
|
+
readonly authoringContributions: AuthoringContributions | undefined;
|
|
387
|
+
readonly entityContext: AuthoringEntityContext;
|
|
388
|
+
readonly diagnostics: ContractSourceDiagnostic[];
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function processEnum2Declarations(input: ProcessEnum2DeclarationsInput): {
|
|
392
|
+
readonly enumHandles: Record<string, EnumTypeHandle>;
|
|
393
|
+
readonly enumTypeDescriptors: Map<string, ColumnDescriptor>;
|
|
394
|
+
} {
|
|
395
|
+
const enumHandles: Record<string, EnumTypeHandle> = {};
|
|
396
|
+
const enumTypeDescriptors = new Map<string, ColumnDescriptor>();
|
|
397
|
+
|
|
398
|
+
if (input.enum2Blocks.length === 0) {
|
|
399
|
+
return { enumHandles, enumTypeDescriptors };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const enum2EntityDescriptor = getAuthoringEntity(input.authoringContributions, ['enum2']);
|
|
403
|
+
if (!enum2EntityDescriptor) {
|
|
404
|
+
for (const decl of input.enum2Blocks) {
|
|
405
|
+
input.diagnostics.push({
|
|
406
|
+
code: 'PSL_ENUM2_MISSING_FACTORY',
|
|
407
|
+
message: `enum2 "${decl.name}" requires an "enum2" entityType factory in the active authoring contributions`,
|
|
408
|
+
sourceId: input.sourceId,
|
|
409
|
+
span: decl.span,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
return { enumHandles, enumTypeDescriptors };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
for (const decl of input.enum2Blocks) {
|
|
416
|
+
const handle = instantiateAuthoringEntityType(
|
|
417
|
+
'enum2',
|
|
418
|
+
enum2EntityDescriptor,
|
|
419
|
+
[decl],
|
|
420
|
+
input.entityContext,
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
if (handle === undefined || handle === null) continue;
|
|
424
|
+
|
|
425
|
+
const enumHandle = blindCast<EnumTypeHandle, 'enum2 factory returns EnumTypeHandle'>(handle);
|
|
426
|
+
enumHandles[decl.name] = enumHandle;
|
|
427
|
+
enumTypeDescriptors.set(decl.name, {
|
|
428
|
+
codecId: enumHandle.codecId,
|
|
429
|
+
nativeType: enumHandle.nativeType,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return { enumHandles, enumTypeDescriptors };
|
|
434
|
+
}
|
|
435
|
+
|
|
378
436
|
interface ResolveNamedTypeDeclarationsInput {
|
|
379
437
|
readonly declarations: readonly PslNamedTypeDeclaration[];
|
|
380
438
|
readonly sourceId: string;
|
|
@@ -619,6 +677,7 @@ interface BuildModelNodeInput {
|
|
|
619
677
|
readonly diagnostics: ContractSourceDiagnostic[];
|
|
620
678
|
/** Resolved namespace id keyed by model name — used to stamp the target namespace on FKs. */
|
|
621
679
|
readonly modelNamespaceIds: ReadonlyMap<string, string>;
|
|
680
|
+
readonly enum2Handles?: ReadonlyMap<string, EnumTypeHandle>;
|
|
622
681
|
}
|
|
623
682
|
|
|
624
683
|
interface BuildModelNodeResult {
|
|
@@ -650,6 +709,7 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
650
709
|
diagnostics,
|
|
651
710
|
sourceId,
|
|
652
711
|
scalarTypeDescriptors: input.scalarTypeDescriptors,
|
|
712
|
+
...ifDefined('enum2Handles', input.enum2Handles),
|
|
653
713
|
});
|
|
654
714
|
|
|
655
715
|
const inlineIdFields = resolvedFields.filter((field) => field.isId);
|
|
@@ -1320,14 +1380,18 @@ function buildModelNodeFromPsl(input: BuildModelNodeInput): BuildModelNodeResult
|
|
|
1320
1380
|
modelNode: {
|
|
1321
1381
|
modelName: model.name,
|
|
1322
1382
|
tableName,
|
|
1323
|
-
fields: resolvedFields.map((resolvedField) =>
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1383
|
+
fields: resolvedFields.map((resolvedField) => {
|
|
1384
|
+
const enumHandle = input.enum2Handles?.get(resolvedField.field.typeName);
|
|
1385
|
+
return {
|
|
1386
|
+
fieldName: resolvedField.field.name,
|
|
1387
|
+
columnName: resolvedField.columnName,
|
|
1388
|
+
descriptor: resolvedField.descriptor,
|
|
1389
|
+
nullable: resolvedField.field.optional,
|
|
1390
|
+
...ifDefined('default', resolvedField.defaultValue),
|
|
1391
|
+
...ifDefined('executionDefaults', resolvedField.executionDefaults),
|
|
1392
|
+
...ifDefined('enumTypeHandle', enumHandle),
|
|
1393
|
+
};
|
|
1394
|
+
}),
|
|
1331
1395
|
...ifDefined('id', primaryKey),
|
|
1332
1396
|
...(uniqueConstraints.length > 0 ? { uniques: uniqueConstraints } : {}),
|
|
1333
1397
|
...(indexNodes.length > 0 ? { indexes: indexNodes } : {}),
|
|
@@ -2006,6 +2070,68 @@ export function interpretPslDocumentToSqlContract(
|
|
|
2006
2070
|
}
|
|
2007
2071
|
}
|
|
2008
2072
|
|
|
2073
|
+
const topLevelEnum2s = input.document.ast.namespaces
|
|
2074
|
+
.filter((ns) => ns.name === UNSPECIFIED_PSL_NAMESPACE_NAME)
|
|
2075
|
+
.flatMap((ns) => namespacePslExtensionBlocks(ns).filter((b) => b.kind === 'enum2'));
|
|
2076
|
+
for (const ns of input.document.ast.namespaces) {
|
|
2077
|
+
if (ns.name === UNSPECIFIED_PSL_NAMESPACE_NAME) continue;
|
|
2078
|
+
const nsEnum2s = namespacePslExtensionBlocks(ns).filter((b) => b.kind === 'enum2');
|
|
2079
|
+
if (nsEnum2s.length === 0) continue;
|
|
2080
|
+
for (const decl of nsEnum2s) {
|
|
2081
|
+
diagnostics.push({
|
|
2082
|
+
code: 'PSL_ENUM2_NAMESPACE_NOT_SUPPORTED',
|
|
2083
|
+
message: `enum2 "${decl.name}" inside namespace "${ns.name}" is not supported; declare enum2 at the top level`,
|
|
2084
|
+
sourceId,
|
|
2085
|
+
span: decl.span,
|
|
2086
|
+
});
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
const enum2Result = processEnum2Declarations({
|
|
2091
|
+
enum2Blocks: topLevelEnum2s,
|
|
2092
|
+
sourceId,
|
|
2093
|
+
authoringContributions: input.authoringContributions,
|
|
2094
|
+
entityContext: {
|
|
2095
|
+
family: input.target.familyId,
|
|
2096
|
+
target: input.target.targetId,
|
|
2097
|
+
...ifDefined('codecLookup', input.codecLookup),
|
|
2098
|
+
sourceId,
|
|
2099
|
+
diagnostics: {
|
|
2100
|
+
push: (d) => {
|
|
2101
|
+
diagnostics.push(
|
|
2102
|
+
blindCast<ContractSourceDiagnostic, 'sink diagnostics are span-compatible'>(d),
|
|
2103
|
+
);
|
|
2104
|
+
},
|
|
2105
|
+
},
|
|
2106
|
+
},
|
|
2107
|
+
diagnostics,
|
|
2108
|
+
});
|
|
2109
|
+
|
|
2110
|
+
const collidingEnum2Names = new Set<string>();
|
|
2111
|
+
for (const [name, descriptor] of enum2Result.enumTypeDescriptors) {
|
|
2112
|
+
if (allEnumTypeDescriptors.has(name)) {
|
|
2113
|
+
collidingEnum2Names.add(name);
|
|
2114
|
+
const collision = topLevelEnum2s.find((e) => e.name === name);
|
|
2115
|
+
diagnostics.push({
|
|
2116
|
+
code: 'PSL_ENUM2_DUPLICATE_TYPE_NAME',
|
|
2117
|
+
message: `enum2 "${name}" collides with an existing type name; each type name must be unique`,
|
|
2118
|
+
sourceId,
|
|
2119
|
+
...ifDefined('span', collision?.span),
|
|
2120
|
+
});
|
|
2121
|
+
} else {
|
|
2122
|
+
allEnumTypeDescriptors.set(name, descriptor);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
const validEnum2Handles: Record<string, EnumTypeHandle> = {};
|
|
2127
|
+
for (const [name, handle] of Object.entries(enum2Result.enumHandles)) {
|
|
2128
|
+
if (!collidingEnum2Names.has(name)) {
|
|
2129
|
+
validEnum2Handles[name] = handle;
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
const enum2HandlesByName = new Map(Object.entries(validEnum2Handles));
|
|
2134
|
+
|
|
2009
2135
|
const namedTypeResult = resolveNamedTypeDeclarations({
|
|
2010
2136
|
declarations: input.document.ast.types?.declarations ?? [],
|
|
2011
2137
|
sourceId,
|
|
@@ -2068,6 +2194,7 @@ export function interpretPslDocumentToSqlContract(
|
|
|
2068
2194
|
sourceId,
|
|
2069
2195
|
diagnostics,
|
|
2070
2196
|
modelNamespaceIds,
|
|
2197
|
+
...(enum2HandlesByName.size > 0 ? { enum2Handles: enum2HandlesByName } : {}),
|
|
2071
2198
|
});
|
|
2072
2199
|
modelNodes.push(
|
|
2073
2200
|
namespaceId !== undefined ? { ...result.modelNode, namespaceId } : result.modelNode,
|
|
@@ -2162,6 +2289,7 @@ export function interpretPslDocumentToSqlContract(
|
|
|
2162
2289
|
...(Object.keys(namespaceEnumStorageTypes).length > 0
|
|
2163
2290
|
? { namespaceTypes: namespaceEnumStorageTypes }
|
|
2164
2291
|
: {}),
|
|
2292
|
+
...(Object.keys(validEnum2Handles).length > 0 ? { enums: validEnum2Handles } : {}),
|
|
2165
2293
|
...ifDefined('createNamespace', input.createNamespace),
|
|
2166
2294
|
models: stiColumnModelNodes.map((model) => ({
|
|
2167
2295
|
...model,
|
|
@@ -2233,6 +2361,7 @@ export function interpretPslDocumentToSqlContract(
|
|
|
2233
2361
|
patchedModels[modelCoordinateKey(namespaceId, modelName)] ?? model,
|
|
2234
2362
|
]),
|
|
2235
2363
|
),
|
|
2364
|
+
...(namespaceSlice.enum !== undefined ? { enum: namespaceSlice.enum } : {}),
|
|
2236
2365
|
...(namespaceSlice.valueObjects !== undefined
|
|
2237
2366
|
? { valueObjects: namespaceSlice.valueObjects }
|
|
2238
2367
|
: {}),
|
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;
|
|
@@ -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 lowerEnum2DefaultForField(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_ENUM2_DEFAULT_MUST_BE_MEMBER_NAME',
|
|
56
|
+
message: `Field "${input.modelName}.${input.fieldName}" @default on an enum2 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_ENUM2_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 enum2Handles?: ReadonlyMap<string, EnumTypeHandle>;
|
|
79
142
|
}
|
|
80
143
|
|
|
81
144
|
const BUILTIN_FIELD_ATTRIBUTE_NAMES: ReadonlySet<string> = new Set([
|
|
@@ -225,6 +288,7 @@ export function collectResolvedFields(input: CollectResolvedFieldsInput): Resolv
|
|
|
225
288
|
diagnostics,
|
|
226
289
|
sourceId,
|
|
227
290
|
scalarTypeDescriptors,
|
|
291
|
+
enum2Handles,
|
|
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 enum2Handle = enum2Handles?.get(field.typeName);
|
|
418
|
+
const loweredDefault: LoweredFieldDefault = defaultAttribute
|
|
419
|
+
? enum2Handle
|
|
420
|
+
? lowerEnum2DefaultForField({
|
|
421
|
+
modelName: model.name,
|
|
422
|
+
fieldName: field.name,
|
|
423
|
+
defaultAttribute,
|
|
424
|
+
enumHandle: enum2Handle,
|
|
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) {
|