@prisma-next/family-sql 0.16.0-dev.3 → 0.16.0-dev.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/control.d.mts +1 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +108 -33
- package/dist/control.mjs.map +1 -1
- package/dist/diff.d.mts +1 -1
- package/dist/errors-ZGKTAYsm.mjs +9 -0
- package/dist/errors-ZGKTAYsm.mjs.map +1 -0
- package/dist/ir.d.mts.map +1 -1
- package/dist/ir.mjs +1 -1
- package/dist/migration.d.mts +1 -1
- package/dist/psl-infer.d.mts +3 -5
- package/dist/psl-infer.d.mts.map +1 -1
- package/dist/psl-infer.mjs +11 -8
- package/dist/psl-infer.mjs.map +1 -1
- package/dist/{sql-contract-serializer-C75cfMSS.mjs → sql-contract-serializer-othnJUZ_.mjs} +7 -2
- package/dist/sql-contract-serializer-othnJUZ_.mjs.map +1 -0
- package/dist/{types-6JMCRorL.d.mts → types-DhAmOoxA.d.mts} +11 -4
- package/dist/{types-6JMCRorL.d.mts.map → types-DhAmOoxA.d.mts.map} +1 -1
- package/dist/{verify-C-G0obRm.mjs → verify-DuuJFiTm.mjs} +7 -2
- package/dist/verify-DuuJFiTm.mjs.map +1 -0
- package/dist/verify.d.mts.map +1 -1
- package/dist/verify.mjs +1 -1
- package/package.json +21 -21
- package/src/core/control-instance.ts +50 -24
- package/src/core/errors.ts +22 -0
- package/src/core/ir/sql-contract-serializer-base.ts +8 -1
- package/src/core/migrations/contract-to-schema-ir.ts +78 -17
- package/src/core/migrations/types.ts +10 -3
- package/src/core/psl-contract-infer/name-transforms.ts +0 -12
- package/src/core/psl-contract-infer/printer-config.ts +2 -3
- package/src/core/psl-contract-infer/relation-inference.ts +23 -1
- package/src/core/verify.ts +10 -1
- package/src/exports/psl-infer.ts +1 -2
- package/dist/sql-contract-serializer-C75cfMSS.mjs.map +0 -1
- package/dist/verify-C-G0obRm.mjs.map +0 -1
package/dist/diff.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as NativeTypeNormalizer, o as arraysEqual } from "./control-adapter-CW7FdxeS.mjs";
|
|
2
|
-
import { n as CodecControlHooks } from "./types-
|
|
2
|
+
import { n as CodecControlHooks } from "./types-DhAmOoxA.mjs";
|
|
3
3
|
import { t as SqlSchemaDiffFn } from "./schema-differ-C8OHo1V5.mjs";
|
|
4
4
|
import { DiffSubjectGranularity, SchemaDiffIssue, VerifierIssueCategory, VerifyDatabaseSchemaResult } from "@prisma-next/framework-components/control";
|
|
5
5
|
import { Contract, ControlPolicy } from "@prisma-next/contract/types";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { structuredError } from "@prisma-next/utils/structured-error";
|
|
2
|
+
//#region src/core/errors.ts
|
|
3
|
+
function sqlFamilyError(code, message, options) {
|
|
4
|
+
return structuredError(code, message, options);
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { sqlFamilyError as t };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=errors-ZGKTAYsm.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-ZGKTAYsm.mjs","names":[],"sources":["../src/core/errors.ts"],"sourcesContent":["import type { StructuredError, StructuredErrorOptions } from '@prisma-next/utils/structured-error';\nimport { structuredError } from '@prisma-next/utils/structured-error';\n\ntype SqlFamilyErrorCode =\n | 'CONTRACT.ENUM_INVALID'\n | 'CONTRACT.ENUM_UNKNOWN'\n | 'CONTRACT.FOREIGN_KEY_INVALID'\n | 'CONTRACT.INFER_UNSUPPORTED'\n | 'CONTRACT.MARKER_ROW_CORRUPT'\n | 'CONTRACT.NAMESPACE_UNKNOWN'\n | 'CONTRACT.PACK_CONTRIBUTION_INVALID'\n | 'CONTRACT.TABLE_AMBIGUOUS'\n | 'CONTRACT.TYPE_UNKNOWN'\n | 'MIGRATION.MARKER_CAS_FAILURE';\n\nexport function sqlFamilyError(\n code: SqlFamilyErrorCode,\n message: string,\n options?: StructuredErrorOptions,\n): StructuredError {\n return structuredError(code, message, options);\n}\n"],"mappings":";;AAeA,SAAgB,eACd,MACA,SACA,SACiB;CACjB,OAAO,gBAAgB,MAAM,SAAS,OAAO;AAC/C"}
|
package/dist/ir.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ir.d.mts","names":[],"sources":["../src/core/ir/sql-contract-serializer-base.ts","../src/core/ir/sql-contract-serializer.ts","../src/core/ir/sql-schema-verifier-base.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"ir.d.mts","names":[],"sources":["../src/core/ir/sql-contract-serializer-base.ts","../src/core/ir/sql-contract-serializer.ts","../src/core/ir/sql-schema-verifier-base.ts"],"mappings":";;;;;;KAoCY,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;uBA0BnB,0BAA0B,kBAAkB,SAAS,wBAC9D,mBAAmB;qBAMT,yBAAyB,oBAE1C;mBANa;mBACA;cAGI,0BAAyB,oBAE1C,4BAEF,2BAA0B;EAO5B,oBAAoB,UAAU,YAAY,WAAW,gBAAgB;EAMrE,kBAAkB,UAAU,YAAY;EAIxC,6DAAmB;EAEnB,qDAAW;YAED,0BAA0B,gBAAgB,SAAS;YAOnD,kBAAkB,WAAW,SAAS,cAAc,SAAS;YAuC7D,uBACR,YAAY,SAAS,eAAe,4BACnC,SAAS,eAAe;YAoBjB,yBACR,cACA,KAAK,0BACJ,YAAY;YA+BL,wBAAwB,OAAO,sBAAsB;YAkBrD,wBAAwB,UAAU,SAAS,cAAc;;;;;;;;;;;YAczD,0BACR,SAAS,SAAS,eAAe,SAAS,6BACzC,eAAe,eAAe;UAazB;YAQE,oBAAoB,iBAAiB;UAOvC;;;;;;;;;;;;;;;;;;cChPG,8BAA8B,0BAA0B,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;uBCSxD,sBAAsB,WAAW,oBAC1C,eAAe,WAAW;EAErC,aAAa,SAAS,oBAAoB,WAAW,WAAW;;;;;;;qBAa7C,sBACjB,SAAS,oBAAoB,WAAW,oBAC9B;;;;;;qBAOO,uBACjB,SAAS,oBAAoB,WAAW,oBAC9B"}
|
package/dist/ir.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as SqlContractSerializerBase, t as SqlContractSerializer } from "./sql-contract-serializer-
|
|
1
|
+
import { n as SqlContractSerializerBase, t as SqlContractSerializer } from "./sql-contract-serializer-othnJUZ_.mjs";
|
|
2
2
|
//#region src/core/ir/sql-schema-verifier-base.ts
|
|
3
3
|
/**
|
|
4
4
|
* SQL family `SchemaVerifier` abstract base. Centralises the SQL-shared
|
package/dist/migration.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as SqlMigrationPlanOperation, w as SqlPlanTargetDetails } from "./types-
|
|
1
|
+
import { f as SqlMigrationPlanOperation, w as SqlPlanTargetDetails } from "./types-DhAmOoxA.mjs";
|
|
2
2
|
import { Contract } from "@prisma-next/contract/types";
|
|
3
3
|
import { SqlStorage } from "@prisma-next/sql-contract/types";
|
|
4
4
|
import { Migration } from "@prisma-next/migration-tools/migration";
|
package/dist/psl-infer.d.mts
CHANGED
|
@@ -30,18 +30,16 @@ declare function toEnumMemberName(value: string): string;
|
|
|
30
30
|
declare function pluralize(word: string): string;
|
|
31
31
|
declare function deriveRelationFieldName(fkColumns: readonly string[], referencedTableName: string): string;
|
|
32
32
|
declare function deriveBackRelationFieldName(childModelName: string, isOneToOne: boolean): string;
|
|
33
|
-
declare function toNamedTypeName(columnName: string): string;
|
|
34
33
|
//#endregion
|
|
35
34
|
//#region src/core/psl-contract-infer/printer-config.d.ts
|
|
36
|
-
type
|
|
35
|
+
type PslTypeReference = {
|
|
37
36
|
readonly name: string;
|
|
38
37
|
readonly args?: readonly string[];
|
|
39
38
|
};
|
|
40
39
|
type PslTypeResolution = {
|
|
41
|
-
readonly pslType:
|
|
40
|
+
readonly pslType: PslTypeReference;
|
|
42
41
|
readonly nativeType: string;
|
|
43
42
|
readonly typeParams?: Record<string, unknown>;
|
|
44
|
-
readonly nativeTypeAttribute?: PslNativeTypeAttribute;
|
|
45
43
|
} | {
|
|
46
44
|
readonly unsupported: true;
|
|
47
45
|
readonly nativeType: string;
|
|
@@ -115,5 +113,5 @@ declare function inferRelations(tables: Record<string, SqlTableIR>, modelNameMap
|
|
|
115
113
|
*/
|
|
116
114
|
declare function buildChildRelationField(fieldName: string, parentModelName: string, fk: SqlForeignKeyIR, optional: boolean, relationName?: string, hostTable?: SqlTableIR): RelationField;
|
|
117
115
|
//#endregion
|
|
118
|
-
export { type DefaultMappingOptions, type DefaultMappingResult, type EnumInfo, type InferredRelations, type
|
|
116
|
+
export { type DefaultMappingOptions, type DefaultMappingResult, type EnumInfo, type InferredRelations, type PslPrinterOptions, type PslTypeMap, type PslTypeReference, type PslTypeResolution, type RelationField, buildChildRelationField, deriveBackRelationFieldName, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, pluralize, toEnumMemberName, toEnumName, toFieldName, toModelName };
|
|
119
117
|
//# sourceMappingURL=psl-infer.d.mts.map
|
package/dist/psl-infer.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"psl-infer.d.mts","names":[],"sources":["../src/core/psl-contract-infer/default-mapping.ts","../src/core/psl-contract-infer/name-transforms.ts","../src/core/psl-contract-infer/printer-config.ts","../src/core/psl-contract-infer/raw-default-parser.ts","../src/core/psl-contract-infer/relation-inference.ts"],"mappings":";;;UAOiB;WACN,qBAAqB,SAAS;WAC9B,8BAA8B;;KAG7B;WAAkC;;WAAiC;;iBAE/D,WACd,eAAe,eACf,UAAU,wBACT;;;KCXE;WACM;WACA;;iBA4DK,YAAY,oBAAoB;iBAqBhC,YAAY,qBAAqB;iBAqBjC,WAAW,qBAAqB;;;;;;;iBA6BhC,iBAAiB;iBAOjB,UAAU;iBAIV,wBACd,8BACA;iBAec,4BAA4B,wBAAwB
|
|
1
|
+
{"version":3,"file":"psl-infer.d.mts","names":[],"sources":["../src/core/psl-contract-infer/default-mapping.ts","../src/core/psl-contract-infer/name-transforms.ts","../src/core/psl-contract-infer/printer-config.ts","../src/core/psl-contract-infer/raw-default-parser.ts","../src/core/psl-contract-infer/relation-inference.ts"],"mappings":";;;UAOiB;WACN,qBAAqB,SAAS;WAC9B,8BAA8B;;KAG7B;WAAkC;;WAAiC;;iBAE/D,WACd,eAAe,eACf,UAAU,wBACT;;;KCXE;WACM;WACA;;iBA4DK,YAAY,oBAAoB;iBAqBhC,YAAY,qBAAqB;iBAqBjC,WAAW,qBAAqB;;;;;;;iBA6BhC,iBAAiB;iBAOjB,UAAU;iBAIV,wBACd,8BACA;iBAec,4BAA4B,wBAAwB;;;KCpKxD;WACD;WACA;;KAGC;WAEG,SAAS;WACT;WACA,aAAa;;WAGb;WACA;;UAGE;EACf,QAAQ,oBAAoB,cAAc,0BAA0B;;UAGrD;WACN,WAAW;WACX,aAAa;;UAGP;WACN,SAAS;WACT,iBAAiB;WACjB,WAAW;WACX,mBAAmB,oBAAoB,wBAAwB;;KAG9D;WACD;WACA;;;;;;WAMA;;;;;;WAMA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;WAEA;;;;iBCvBK,gBACd,oBACA,sBACC;;;KCrBS;WACD,kBAAkB,6BAA6B;;iBAG1C,eACd,QAAQ,eAAe,aACvB,cAAc,8BACb;;;;;;;;;;;;;;;;;;;iBAiJa,wBACd,mBACA,yBACA,IAAI,iBACJ,mBACA,uBACA,YAAY,aACX"}
|
package/dist/psl-infer.mjs
CHANGED
|
@@ -150,12 +150,6 @@ function deriveBackRelationFieldName(childModelName, isOneToOne) {
|
|
|
150
150
|
const base = childModelName.charAt(0).toLowerCase() + childModelName.slice(1);
|
|
151
151
|
return isOneToOne ? base : pluralize(base);
|
|
152
152
|
}
|
|
153
|
-
function toNamedTypeName(columnName) {
|
|
154
|
-
let name;
|
|
155
|
-
if (hasSeparators(columnName)) name = snakeToPascalCase(columnName);
|
|
156
|
-
else name = columnName.charAt(0).toUpperCase() + columnName.slice(1);
|
|
157
|
-
return escapeIfNeeded(name);
|
|
158
|
-
}
|
|
159
153
|
//#endregion
|
|
160
154
|
//#region src/core/psl-contract-infer/raw-default-parser.ts
|
|
161
155
|
const NEXTVAL_PATTERN = /^nextval\s*\(/i;
|
|
@@ -302,6 +296,11 @@ function detectOneToOne(fk, table) {
|
|
|
302
296
|
const uniqueCols = [...unique.columns].sort();
|
|
303
297
|
if (uniqueCols.length === fkCols.length && uniqueCols.every((c, i) => c === fkCols[i])) return true;
|
|
304
298
|
}
|
|
299
|
+
for (const index of table.indexes) {
|
|
300
|
+
if (!index.unique || index.partial || index.columns === void 0) continue;
|
|
301
|
+
const indexCols = [...index.columns].sort();
|
|
302
|
+
if (indexCols.length === fkCols.length && indexCols.every((c, i) => c === fkCols[i])) return true;
|
|
303
|
+
}
|
|
305
304
|
return false;
|
|
306
305
|
}
|
|
307
306
|
function deriveRelationName(fk, childRelationFieldName, parentModelName, isSelfRelation) {
|
|
@@ -330,7 +329,11 @@ function deriveRelationName(fk, childRelationFieldName, parentModelName, isSelfR
|
|
|
330
329
|
function buildChildRelationField(fieldName, parentModelName, fk, optional, relationName, hostTable) {
|
|
331
330
|
const onDelete = fk.onDelete && fk.onDelete !== DEFAULT_ON_DELETE ? fk.onDelete : void 0;
|
|
332
331
|
const onUpdate = fk.onUpdate && fk.onUpdate !== DEFAULT_ON_UPDATE ? fk.onUpdate : void 0;
|
|
333
|
-
const index = hostTable && !isBackedByColumnKeys(fk.columns, backingIndexColumnKeys(
|
|
332
|
+
const index = hostTable && !isBackedByColumnKeys(fk.columns, backingIndexColumnKeys({
|
|
333
|
+
indexes: hostTable.indexes.filter((i) => i.where === void 0),
|
|
334
|
+
uniques: hostTable.uniques,
|
|
335
|
+
primaryKey: hostTable.primaryKey
|
|
336
|
+
})) ? false : void 0;
|
|
334
337
|
return {
|
|
335
338
|
fieldName,
|
|
336
339
|
typeName: parentModelName,
|
|
@@ -360,6 +363,6 @@ function addRelationField(map, tableName, field) {
|
|
|
360
363
|
else map.set(tableName, [field]);
|
|
361
364
|
}
|
|
362
365
|
//#endregion
|
|
363
|
-
export { buildChildRelationField, deriveBackRelationFieldName, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, pluralize, toEnumMemberName, toEnumName, toFieldName, toModelName
|
|
366
|
+
export { buildChildRelationField, deriveBackRelationFieldName, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, pluralize, toEnumMemberName, toEnumName, toFieldName, toModelName };
|
|
364
367
|
|
|
365
368
|
//# sourceMappingURL=psl-infer.mjs.map
|
package/dist/psl-infer.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"psl-infer.mjs","names":[],"sources":["../src/core/psl-contract-infer/default-mapping.ts","../src/core/psl-contract-infer/name-transforms.ts","../src/core/psl-contract-infer/raw-default-parser.ts","../src/core/psl-contract-infer/relation-inference.ts"],"sourcesContent":["import type { ColumnDefault } from '@prisma-next/contract/types';\n\nconst DEFAULT_FUNCTION_ATTRIBUTES: Readonly<Record<string, string>> = {\n 'autoincrement()': '@default(autoincrement())',\n 'now()': '@default(now())',\n};\n\nexport interface DefaultMappingOptions {\n readonly functionAttributes?: Readonly<Record<string, string>>;\n readonly fallbackFunctionAttribute?: ((expression: string) => string | undefined) | undefined;\n}\n\nexport type DefaultMappingResult = { readonly attribute: string } | { readonly comment: string };\n\nexport function mapDefault(\n columnDefault: ColumnDefault,\n options?: DefaultMappingOptions,\n): DefaultMappingResult {\n switch (columnDefault.kind) {\n case 'literal':\n return { attribute: `@default(${formatLiteralValue(columnDefault.value)})` };\n case 'function': {\n const attribute =\n options?.functionAttributes?.[columnDefault.expression] ??\n DEFAULT_FUNCTION_ATTRIBUTES[columnDefault.expression] ??\n options?.fallbackFunctionAttribute?.(columnDefault.expression);\n return attribute\n ? { attribute }\n : { comment: `// Raw default: ${columnDefault.expression.replace(/[\\r\\n]+/g, ' ')}` };\n }\n }\n}\n\nfunction formatLiteralValue(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n\n switch (typeof value) {\n case 'boolean':\n case 'number':\n return String(value);\n case 'string':\n return quoteString(value);\n default:\n return quoteString(JSON.stringify(value));\n }\n}\n\nfunction quoteString(str: string): string {\n return `\"${escapeString(str)}\"`;\n}\n\nfunction escapeString(str: string): string {\n return JSON.stringify(str).slice(1, -1);\n}\n","import pluralizeLib from 'pluralize';\n\nconst PSL_RESERVED_WORDS = new Set(['model', 'enum', 'types', 'type', 'generator', 'datasource']);\n\nconst IDENTIFIER_PART_PATTERN = /[A-Za-z0-9]+/g;\n\ntype NameResult = {\n readonly name: string;\n readonly map?: string;\n};\n\nfunction hasSeparators(input: string): boolean {\n return /[^A-Za-z0-9]/.test(input);\n}\n\nfunction extractIdentifierParts(input: string): string[] {\n return input.match(IDENTIFIER_PART_PATTERN) ?? [];\n}\n\nfunction createSyntheticIdentifier(input: string): string {\n let hash = 2166136261;\n\n for (const char of input) {\n hash ^= char.codePointAt(0) ?? 0;\n hash = Math.imul(hash, 16777619);\n }\n\n return `x${(hash >>> 0).toString(16)}`;\n}\n\nfunction sanitizeIdentifierCharacters(input: string): string {\n const sanitized = input.replace(/[^\\w]/g, '');\n return sanitized.length > 0 ? sanitized : createSyntheticIdentifier(input);\n}\n\nfunction capitalize(word: string): string {\n return word.charAt(0).toUpperCase() + word.slice(1);\n}\n\nfunction snakeToPascalCase(input: string): string {\n const parts = extractIdentifierParts(input);\n if (parts.length === 0) {\n return capitalize(sanitizeIdentifierCharacters(input));\n }\n return parts.map(capitalize).join('');\n}\n\nfunction snakeToCamelCase(input: string): string {\n const parts = extractIdentifierParts(input);\n if (parts.length === 0) {\n return sanitizeIdentifierCharacters(input);\n }\n const [firstPart = input, ...rest] = parts;\n return firstPart.charAt(0).toLowerCase() + firstPart.slice(1) + rest.map(capitalize).join('');\n}\n\nfunction needsEscaping(name: string): boolean {\n return PSL_RESERVED_WORDS.has(name.toLowerCase()) || /^\\d/.test(name);\n}\n\nfunction escapeName(name: string): string {\n return `_${name}`;\n}\n\nfunction escapeIfNeeded(name: string): string {\n return needsEscaping(name) ? escapeName(name) : name;\n}\n\nexport function toModelName(tableName: string): NameResult {\n let name: string;\n\n if (hasSeparators(tableName)) {\n name = snakeToPascalCase(tableName);\n } else {\n name = tableName.charAt(0).toUpperCase() + tableName.slice(1);\n }\n\n if (needsEscaping(name)) {\n const escaped = escapeName(name);\n return { name: escaped, map: tableName };\n }\n\n if (name !== tableName) {\n return { name, map: tableName };\n }\n\n return { name };\n}\n\nexport function toFieldName(columnName: string): NameResult {\n let name: string;\n\n if (hasSeparators(columnName)) {\n name = snakeToCamelCase(columnName);\n } else {\n name = columnName.charAt(0).toLowerCase() + columnName.slice(1);\n }\n\n if (needsEscaping(name)) {\n const escaped = escapeName(name);\n return { name: escaped, map: columnName };\n }\n\n if (name !== columnName) {\n return { name, map: columnName };\n }\n\n return { name };\n}\n\nexport function toEnumName(pgTypeName: string): NameResult {\n let name: string;\n\n if (hasSeparators(pgTypeName)) {\n name = snakeToPascalCase(pgTypeName);\n } else {\n name = pgTypeName.charAt(0).toUpperCase() + pgTypeName.slice(1);\n }\n\n if (needsEscaping(name)) {\n const escaped = escapeName(name);\n return { name: escaped, map: pgTypeName };\n }\n\n if (name !== pgTypeName) {\n return { name, map: pgTypeName };\n }\n\n return { name };\n}\n\nconst VALID_IDENTIFIER_PATTERN = /^[A-Za-z_]\\w*$/;\n\n/**\n * PSL member name for a native-enum value. The value itself always prints\n * explicitly (`member = \"value\"`), so the returned name never needs a map:\n * a value that already is a valid, non-reserved identifier is kept verbatim\n * (case included); anything else is camelCased/escaped like a field name.\n */\nexport function toEnumMemberName(value: string): string {\n if (VALID_IDENTIFIER_PATTERN.test(value) && !needsEscaping(value)) {\n return value;\n }\n return escapeIfNeeded(snakeToCamelCase(value));\n}\n\nexport function pluralize(word: string): string {\n return pluralizeLib.plural(word);\n}\n\nexport function deriveRelationFieldName(\n fkColumns: readonly string[],\n referencedTableName: string,\n): string {\n if (fkColumns.length === 1) {\n const [col = referencedTableName] = fkColumns;\n const stripped = col.replace(/_id$/i, '').replace(/Id$/, '');\n\n if (stripped.length > 0 && stripped !== col) {\n return escapeIfNeeded(snakeToCamelCase(stripped));\n }\n return escapeIfNeeded(snakeToCamelCase(referencedTableName));\n }\n\n return escapeIfNeeded(snakeToCamelCase(referencedTableName));\n}\n\nexport function deriveBackRelationFieldName(childModelName: string, isOneToOne: boolean): string {\n const base = childModelName.charAt(0).toLowerCase() + childModelName.slice(1);\n return isOneToOne ? base : pluralize(base);\n}\n\nexport function toNamedTypeName(columnName: string): string {\n let name: string;\n\n if (hasSeparators(columnName)) {\n name = snakeToPascalCase(columnName);\n } else {\n name = columnName.charAt(0).toUpperCase() + columnName.slice(1);\n }\n\n return escapeIfNeeded(name);\n}\n","import type { ColumnDefault } from '@prisma-next/contract/types';\n\nconst NEXTVAL_PATTERN = /^nextval\\s*\\(/i;\nconst NOW_FUNCTION_PATTERN = /^(now\\s*\\(\\s*\\)|CURRENT_TIMESTAMP)$/i;\nconst CLOCK_TIMESTAMP_PATTERN = /^clock_timestamp\\s*\\(\\s*\\)$/i;\nconst TIMESTAMP_CAST_SUFFIX = /::timestamp(?:tz|\\s+(?:with|without)\\s+time\\s+zone)?$/i;\nconst TEXT_CAST_SUFFIX = /::text$/i;\nconst NOW_LITERAL_PATTERN = /^'now'$/i;\nconst UUID_PATTERN = /^gen_random_uuid\\s*\\(\\s*\\)$/i;\nconst UUID_OSSP_PATTERN = /^uuid_generate_v4\\s*\\(\\s*\\)$/i;\nconst NULL_PATTERN = /^NULL(?:::.+)?$/i;\nconst TRUE_PATTERN = /^true$/i;\nconst FALSE_PATTERN = /^false$/i;\nconst NUMERIC_PATTERN = /^-?\\d+(\\.\\d+)?$/;\nconst JSON_CAST_SUFFIX = /::jsonb?$/i;\nconst STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:\"[^\"]+\"|[\\w\\s]+)(?:\\(\\d+\\))?)?$/;\n\nfunction canonicalizeTimestampDefault(expr: string): string | undefined {\n if (NOW_FUNCTION_PATTERN.test(expr)) return 'now()';\n if (CLOCK_TIMESTAMP_PATTERN.test(expr)) return 'clock_timestamp()';\n\n if (!TIMESTAMP_CAST_SUFFIX.test(expr)) return undefined;\n\n let inner = expr.replace(TIMESTAMP_CAST_SUFFIX, '').trim();\n if (inner.startsWith('(') && inner.endsWith(')')) {\n inner = inner.slice(1, -1).trim();\n }\n\n if (NOW_FUNCTION_PATTERN.test(inner)) return 'now()';\n if (CLOCK_TIMESTAMP_PATTERN.test(inner)) return 'clock_timestamp()';\n\n inner = inner.replace(TEXT_CAST_SUFFIX, '').trim();\n if (NOW_LITERAL_PATTERN.test(inner)) return 'now()';\n\n return undefined;\n}\n\nexport function parseRawDefault(\n rawDefault: string,\n nativeType?: string,\n): ColumnDefault | undefined {\n const trimmed = rawDefault.trim();\n const normalizedType = nativeType?.toLowerCase();\n\n if (NEXTVAL_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'autoincrement()' };\n }\n\n const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);\n if (canonicalTimestamp) {\n return { kind: 'function', expression: canonicalTimestamp };\n }\n\n if (UUID_PATTERN.test(trimmed) || UUID_OSSP_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'gen_random_uuid()' };\n }\n\n if (NULL_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: null };\n }\n\n if (TRUE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: true };\n }\n\n if (FALSE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: false };\n }\n\n if (NUMERIC_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: Number(trimmed) };\n }\n\n const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);\n if (stringMatch?.[1] !== undefined) {\n const unescaped = stringMatch[1].replace(/''/g, \"'\");\n if (normalizedType === 'json' || normalizedType === 'jsonb') {\n if (JSON_CAST_SUFFIX.test(trimmed)) {\n return { kind: 'function', expression: trimmed };\n }\n try {\n return { kind: 'literal', value: JSON.parse(unescaped) };\n } catch {\n // Fall through to the string form for malformed/non-JSON values.\n }\n }\n return { kind: 'literal', value: unescaped };\n }\n\n return { kind: 'function', expression: trimmed };\n}\n","import {\n backingIndexColumnKeys,\n isBackedByColumnKeys,\n} from '@prisma-next/sql-contract/foreign-key-materialization';\nimport type { SqlForeignKeyIR, SqlTableIR } from '@prisma-next/sql-schema-ir/types';\nimport { deriveBackRelationFieldName, deriveRelationFieldName, pluralize } from './name-transforms';\nimport type { RelationField } from './printer-config';\n\nconst DEFAULT_ON_DELETE = 'noAction';\nconst DEFAULT_ON_UPDATE = 'noAction';\n\nconst REFERENTIAL_ACTION_PSL: Record<string, string> = {\n noAction: 'NoAction',\n restrict: 'Restrict',\n cascade: 'Cascade',\n setNull: 'SetNull',\n setDefault: 'SetDefault',\n};\n\nexport type InferredRelations = {\n readonly relationsByTable: ReadonlyMap<string, readonly RelationField[]>;\n};\n\nexport function inferRelations(\n tables: Record<string, SqlTableIR>,\n modelNameMap: ReadonlyMap<string, string>,\n): InferredRelations {\n const relationsByTable = new Map<string, RelationField[]>();\n\n const fkCountByPair = new Map<string, number>();\n for (const table of Object.values(tables)) {\n for (const fk of table.foreignKeys) {\n const pairKey = `${table.name}→${fk.referencedTable}`;\n fkCountByPair.set(pairKey, (fkCountByPair.get(pairKey) ?? 0) + 1);\n }\n }\n\n const usedFieldNames = new Map<string, Set<string>>();\n for (const table of Object.values(tables)) {\n const names = new Set<string>();\n for (const col of Object.values(table.columns)) {\n names.add(col.name);\n }\n usedFieldNames.set(table.name, names);\n }\n\n for (const table of Object.values(tables)) {\n for (const fk of table.foreignKeys) {\n const childTableName = table.name;\n const parentTableName = fk.referencedTable;\n const childUsed = usedFieldNames.get(childTableName) as Set<string>;\n const childModelName = modelNameMap.get(childTableName) ?? childTableName;\n const parentModelName = modelNameMap.get(parentTableName) ?? parentTableName;\n const pairKey = `${childTableName}→${parentTableName}`;\n const isSelfRelation = childTableName === parentTableName;\n const needsRelationName = (fkCountByPair.get(pairKey) as number) > 1 || isSelfRelation;\n\n const isOneToOne = detectOneToOne(fk, table);\n\n const childRelFieldName = resolveUniqueFieldName(\n deriveRelationFieldName(fk.columns, parentTableName),\n childUsed,\n parentModelName,\n );\n const relationName = needsRelationName\n ? deriveRelationName(fk, childRelFieldName, parentModelName, isSelfRelation)\n : undefined;\n const childOptional = fk.columns.some(\n (columnName) => table.columns[columnName]?.nullable ?? false,\n );\n\n const childRelField = buildChildRelationField(\n childRelFieldName,\n parentModelName,\n fk,\n childOptional,\n relationName,\n table,\n );\n\n addRelationField(relationsByTable, childTableName, childRelField);\n childUsed.add(childRelFieldName);\n\n const parentUsed = usedFieldNames.get(parentTableName) ?? new Set();\n usedFieldNames.set(parentTableName, parentUsed);\n\n const backRelFieldName = resolveUniqueFieldName(\n deriveBackRelationFieldName(childModelName, isOneToOne),\n parentUsed,\n childModelName,\n );\n\n const backRelField: RelationField = {\n fieldName: backRelFieldName,\n typeName: childModelName,\n optional: isOneToOne,\n list: !isOneToOne,\n relationName,\n };\n\n addRelationField(relationsByTable, parentTableName, backRelField);\n parentUsed.add(backRelFieldName);\n }\n }\n\n return { relationsByTable };\n}\n\nfunction detectOneToOne(fk: SqlForeignKeyIR, table: SqlTableIR): boolean {\n const fkCols = [...fk.columns].sort();\n\n if (table.primaryKey) {\n const pkCols = [...table.primaryKey.columns].sort();\n if (pkCols.length === fkCols.length && pkCols.every((c, i) => c === fkCols[i])) {\n return true;\n }\n }\n\n for (const unique of table.uniques) {\n const uniqueCols = [...unique.columns].sort();\n if (uniqueCols.length === fkCols.length && uniqueCols.every((c, i) => c === fkCols[i])) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction deriveRelationName(\n fk: SqlForeignKeyIR,\n childRelationFieldName: string,\n parentModelName: string,\n isSelfRelation: boolean,\n): string {\n if (fk.name) {\n return fk.name;\n }\n if (isSelfRelation) {\n return `${childRelationFieldName.charAt(0).toUpperCase() + childRelationFieldName.slice(1)}${pluralize(parentModelName)}`;\n }\n return fk.columns.join('_');\n}\n\n/**\n * Builds the child-side {@link RelationField} for a single foreign key:\n * `typeName` is the parent model name, `fields`/`references` are the FK's raw\n * columns, and `onDelete`/`onUpdate` are normalized to their PSL spelling.\n * Exported so a caller resolving a foreign key against a model outside\n * `tables` (e.g. a cross-space reference into another contract) can reuse the\n * same normalization instead of duplicating it.\n *\n * `hostTable` is the table the FK is declared on (i.e. `table`, not the\n * referenced parent) — its own indexes/uniques/primary key are what a\n * backing index for this FK would be. When none of them exactly match the\n * FK's source columns (in order), `index: false` is stamped so the emitted\n * `@relation` opts out of the framework's default derived backing-index\n * expectation, matching what `db verify` will find live. Passing the table\n * is optional so existing single-FK callers (e.g. cross-space resolution\n * before a host table reference is threaded through) can omit it and keep\n * the framework default.\n */\nexport function buildChildRelationField(\n fieldName: string,\n parentModelName: string,\n fk: SqlForeignKeyIR,\n optional: boolean,\n relationName?: string,\n hostTable?: SqlTableIR,\n): RelationField {\n const onDelete = fk.onDelete && fk.onDelete !== DEFAULT_ON_DELETE ? fk.onDelete : undefined;\n const onUpdate = fk.onUpdate && fk.onUpdate !== DEFAULT_ON_UPDATE ? fk.onUpdate : undefined;\n const index =\n hostTable && !isBackedByColumnKeys(fk.columns, backingIndexColumnKeys(hostTable))\n ? false\n : undefined;\n\n return {\n fieldName,\n typeName: parentModelName,\n referencedTableName: fk.referencedTable,\n optional,\n list: false,\n relationName,\n fkName: fk.name,\n fields: fk.columns,\n references: fk.referencedColumns,\n onDelete: onDelete ? REFERENTIAL_ACTION_PSL[onDelete] : undefined,\n onUpdate: onUpdate ? REFERENTIAL_ACTION_PSL[onUpdate] : undefined,\n index,\n };\n}\n\nfunction resolveUniqueFieldName(\n desired: string,\n usedNames: ReadonlySet<string>,\n fallbackSuffix: string,\n): string {\n if (!usedNames.has(desired)) {\n return desired;\n }\n\n const withSuffix = `${desired}${fallbackSuffix}`;\n if (!usedNames.has(withSuffix)) {\n return withSuffix;\n }\n\n let counter = 2;\n while (usedNames.has(`${desired}${counter}`)) {\n counter++;\n }\n return `${desired}${counter}`;\n}\n\nfunction addRelationField(\n map: Map<string, RelationField[]>,\n tableName: string,\n field: RelationField,\n): void {\n const existing = map.get(tableName);\n if (existing) {\n existing.push(field);\n } else {\n map.set(tableName, [field]);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"psl-infer.mjs","names":[],"sources":["../src/core/psl-contract-infer/default-mapping.ts","../src/core/psl-contract-infer/name-transforms.ts","../src/core/psl-contract-infer/raw-default-parser.ts","../src/core/psl-contract-infer/relation-inference.ts"],"sourcesContent":["import type { ColumnDefault } from '@prisma-next/contract/types';\n\nconst DEFAULT_FUNCTION_ATTRIBUTES: Readonly<Record<string, string>> = {\n 'autoincrement()': '@default(autoincrement())',\n 'now()': '@default(now())',\n};\n\nexport interface DefaultMappingOptions {\n readonly functionAttributes?: Readonly<Record<string, string>>;\n readonly fallbackFunctionAttribute?: ((expression: string) => string | undefined) | undefined;\n}\n\nexport type DefaultMappingResult = { readonly attribute: string } | { readonly comment: string };\n\nexport function mapDefault(\n columnDefault: ColumnDefault,\n options?: DefaultMappingOptions,\n): DefaultMappingResult {\n switch (columnDefault.kind) {\n case 'literal':\n return { attribute: `@default(${formatLiteralValue(columnDefault.value)})` };\n case 'function': {\n const attribute =\n options?.functionAttributes?.[columnDefault.expression] ??\n DEFAULT_FUNCTION_ATTRIBUTES[columnDefault.expression] ??\n options?.fallbackFunctionAttribute?.(columnDefault.expression);\n return attribute\n ? { attribute }\n : { comment: `// Raw default: ${columnDefault.expression.replace(/[\\r\\n]+/g, ' ')}` };\n }\n }\n}\n\nfunction formatLiteralValue(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n\n switch (typeof value) {\n case 'boolean':\n case 'number':\n return String(value);\n case 'string':\n return quoteString(value);\n default:\n return quoteString(JSON.stringify(value));\n }\n}\n\nfunction quoteString(str: string): string {\n return `\"${escapeString(str)}\"`;\n}\n\nfunction escapeString(str: string): string {\n return JSON.stringify(str).slice(1, -1);\n}\n","import pluralizeLib from 'pluralize';\n\nconst PSL_RESERVED_WORDS = new Set(['model', 'enum', 'types', 'type', 'generator', 'datasource']);\n\nconst IDENTIFIER_PART_PATTERN = /[A-Za-z0-9]+/g;\n\ntype NameResult = {\n readonly name: string;\n readonly map?: string;\n};\n\nfunction hasSeparators(input: string): boolean {\n return /[^A-Za-z0-9]/.test(input);\n}\n\nfunction extractIdentifierParts(input: string): string[] {\n return input.match(IDENTIFIER_PART_PATTERN) ?? [];\n}\n\nfunction createSyntheticIdentifier(input: string): string {\n let hash = 2166136261;\n\n for (const char of input) {\n hash ^= char.codePointAt(0) ?? 0;\n hash = Math.imul(hash, 16777619);\n }\n\n return `x${(hash >>> 0).toString(16)}`;\n}\n\nfunction sanitizeIdentifierCharacters(input: string): string {\n const sanitized = input.replace(/[^\\w]/g, '');\n return sanitized.length > 0 ? sanitized : createSyntheticIdentifier(input);\n}\n\nfunction capitalize(word: string): string {\n return word.charAt(0).toUpperCase() + word.slice(1);\n}\n\nfunction snakeToPascalCase(input: string): string {\n const parts = extractIdentifierParts(input);\n if (parts.length === 0) {\n return capitalize(sanitizeIdentifierCharacters(input));\n }\n return parts.map(capitalize).join('');\n}\n\nfunction snakeToCamelCase(input: string): string {\n const parts = extractIdentifierParts(input);\n if (parts.length === 0) {\n return sanitizeIdentifierCharacters(input);\n }\n const [firstPart = input, ...rest] = parts;\n return firstPart.charAt(0).toLowerCase() + firstPart.slice(1) + rest.map(capitalize).join('');\n}\n\nfunction needsEscaping(name: string): boolean {\n return PSL_RESERVED_WORDS.has(name.toLowerCase()) || /^\\d/.test(name);\n}\n\nfunction escapeName(name: string): string {\n return `_${name}`;\n}\n\nfunction escapeIfNeeded(name: string): string {\n return needsEscaping(name) ? escapeName(name) : name;\n}\n\nexport function toModelName(tableName: string): NameResult {\n let name: string;\n\n if (hasSeparators(tableName)) {\n name = snakeToPascalCase(tableName);\n } else {\n name = tableName.charAt(0).toUpperCase() + tableName.slice(1);\n }\n\n if (needsEscaping(name)) {\n const escaped = escapeName(name);\n return { name: escaped, map: tableName };\n }\n\n if (name !== tableName) {\n return { name, map: tableName };\n }\n\n return { name };\n}\n\nexport function toFieldName(columnName: string): NameResult {\n let name: string;\n\n if (hasSeparators(columnName)) {\n name = snakeToCamelCase(columnName);\n } else {\n name = columnName.charAt(0).toLowerCase() + columnName.slice(1);\n }\n\n if (needsEscaping(name)) {\n const escaped = escapeName(name);\n return { name: escaped, map: columnName };\n }\n\n if (name !== columnName) {\n return { name, map: columnName };\n }\n\n return { name };\n}\n\nexport function toEnumName(pgTypeName: string): NameResult {\n let name: string;\n\n if (hasSeparators(pgTypeName)) {\n name = snakeToPascalCase(pgTypeName);\n } else {\n name = pgTypeName.charAt(0).toUpperCase() + pgTypeName.slice(1);\n }\n\n if (needsEscaping(name)) {\n const escaped = escapeName(name);\n return { name: escaped, map: pgTypeName };\n }\n\n if (name !== pgTypeName) {\n return { name, map: pgTypeName };\n }\n\n return { name };\n}\n\nconst VALID_IDENTIFIER_PATTERN = /^[A-Za-z_]\\w*$/;\n\n/**\n * PSL member name for a native-enum value. The value itself always prints\n * explicitly (`member = \"value\"`), so the returned name never needs a map:\n * a value that already is a valid, non-reserved identifier is kept verbatim\n * (case included); anything else is camelCased/escaped like a field name.\n */\nexport function toEnumMemberName(value: string): string {\n if (VALID_IDENTIFIER_PATTERN.test(value) && !needsEscaping(value)) {\n return value;\n }\n return escapeIfNeeded(snakeToCamelCase(value));\n}\n\nexport function pluralize(word: string): string {\n return pluralizeLib.plural(word);\n}\n\nexport function deriveRelationFieldName(\n fkColumns: readonly string[],\n referencedTableName: string,\n): string {\n if (fkColumns.length === 1) {\n const [col = referencedTableName] = fkColumns;\n const stripped = col.replace(/_id$/i, '').replace(/Id$/, '');\n\n if (stripped.length > 0 && stripped !== col) {\n return escapeIfNeeded(snakeToCamelCase(stripped));\n }\n return escapeIfNeeded(snakeToCamelCase(referencedTableName));\n }\n\n return escapeIfNeeded(snakeToCamelCase(referencedTableName));\n}\n\nexport function deriveBackRelationFieldName(childModelName: string, isOneToOne: boolean): string {\n const base = childModelName.charAt(0).toLowerCase() + childModelName.slice(1);\n return isOneToOne ? base : pluralize(base);\n}\n","import type { ColumnDefault } from '@prisma-next/contract/types';\n\nconst NEXTVAL_PATTERN = /^nextval\\s*\\(/i;\nconst NOW_FUNCTION_PATTERN = /^(now\\s*\\(\\s*\\)|CURRENT_TIMESTAMP)$/i;\nconst CLOCK_TIMESTAMP_PATTERN = /^clock_timestamp\\s*\\(\\s*\\)$/i;\nconst TIMESTAMP_CAST_SUFFIX = /::timestamp(?:tz|\\s+(?:with|without)\\s+time\\s+zone)?$/i;\nconst TEXT_CAST_SUFFIX = /::text$/i;\nconst NOW_LITERAL_PATTERN = /^'now'$/i;\nconst UUID_PATTERN = /^gen_random_uuid\\s*\\(\\s*\\)$/i;\nconst UUID_OSSP_PATTERN = /^uuid_generate_v4\\s*\\(\\s*\\)$/i;\nconst NULL_PATTERN = /^NULL(?:::.+)?$/i;\nconst TRUE_PATTERN = /^true$/i;\nconst FALSE_PATTERN = /^false$/i;\nconst NUMERIC_PATTERN = /^-?\\d+(\\.\\d+)?$/;\nconst JSON_CAST_SUFFIX = /::jsonb?$/i;\nconst STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:\"[^\"]+\"|[\\w\\s]+)(?:\\(\\d+\\))?)?$/;\n\nfunction canonicalizeTimestampDefault(expr: string): string | undefined {\n if (NOW_FUNCTION_PATTERN.test(expr)) return 'now()';\n if (CLOCK_TIMESTAMP_PATTERN.test(expr)) return 'clock_timestamp()';\n\n if (!TIMESTAMP_CAST_SUFFIX.test(expr)) return undefined;\n\n let inner = expr.replace(TIMESTAMP_CAST_SUFFIX, '').trim();\n if (inner.startsWith('(') && inner.endsWith(')')) {\n inner = inner.slice(1, -1).trim();\n }\n\n if (NOW_FUNCTION_PATTERN.test(inner)) return 'now()';\n if (CLOCK_TIMESTAMP_PATTERN.test(inner)) return 'clock_timestamp()';\n\n inner = inner.replace(TEXT_CAST_SUFFIX, '').trim();\n if (NOW_LITERAL_PATTERN.test(inner)) return 'now()';\n\n return undefined;\n}\n\nexport function parseRawDefault(\n rawDefault: string,\n nativeType?: string,\n): ColumnDefault | undefined {\n const trimmed = rawDefault.trim();\n const normalizedType = nativeType?.toLowerCase();\n\n if (NEXTVAL_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'autoincrement()' };\n }\n\n const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);\n if (canonicalTimestamp) {\n return { kind: 'function', expression: canonicalTimestamp };\n }\n\n if (UUID_PATTERN.test(trimmed) || UUID_OSSP_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'gen_random_uuid()' };\n }\n\n if (NULL_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: null };\n }\n\n if (TRUE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: true };\n }\n\n if (FALSE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: false };\n }\n\n if (NUMERIC_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: Number(trimmed) };\n }\n\n const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);\n if (stringMatch?.[1] !== undefined) {\n const unescaped = stringMatch[1].replace(/''/g, \"'\");\n if (normalizedType === 'json' || normalizedType === 'jsonb') {\n if (JSON_CAST_SUFFIX.test(trimmed)) {\n return { kind: 'function', expression: trimmed };\n }\n try {\n return { kind: 'literal', value: JSON.parse(unescaped) };\n } catch {\n // Fall through to the string form for malformed/non-JSON values.\n }\n }\n return { kind: 'literal', value: unescaped };\n }\n\n return { kind: 'function', expression: trimmed };\n}\n","import {\n backingIndexColumnKeys,\n isBackedByColumnKeys,\n} from '@prisma-next/sql-contract/foreign-key-materialization';\nimport type { SqlForeignKeyIR, SqlTableIR } from '@prisma-next/sql-schema-ir/types';\nimport { deriveBackRelationFieldName, deriveRelationFieldName, pluralize } from './name-transforms';\nimport type { RelationField } from './printer-config';\n\nconst DEFAULT_ON_DELETE = 'noAction';\nconst DEFAULT_ON_UPDATE = 'noAction';\n\nconst REFERENTIAL_ACTION_PSL: Record<string, string> = {\n noAction: 'NoAction',\n restrict: 'Restrict',\n cascade: 'Cascade',\n setNull: 'SetNull',\n setDefault: 'SetDefault',\n};\n\nexport type InferredRelations = {\n readonly relationsByTable: ReadonlyMap<string, readonly RelationField[]>;\n};\n\nexport function inferRelations(\n tables: Record<string, SqlTableIR>,\n modelNameMap: ReadonlyMap<string, string>,\n): InferredRelations {\n const relationsByTable = new Map<string, RelationField[]>();\n\n const fkCountByPair = new Map<string, number>();\n for (const table of Object.values(tables)) {\n for (const fk of table.foreignKeys) {\n const pairKey = `${table.name}→${fk.referencedTable}`;\n fkCountByPair.set(pairKey, (fkCountByPair.get(pairKey) ?? 0) + 1);\n }\n }\n\n const usedFieldNames = new Map<string, Set<string>>();\n for (const table of Object.values(tables)) {\n const names = new Set<string>();\n for (const col of Object.values(table.columns)) {\n names.add(col.name);\n }\n usedFieldNames.set(table.name, names);\n }\n\n for (const table of Object.values(tables)) {\n for (const fk of table.foreignKeys) {\n const childTableName = table.name;\n const parentTableName = fk.referencedTable;\n const childUsed = usedFieldNames.get(childTableName) as Set<string>;\n const childModelName = modelNameMap.get(childTableName) ?? childTableName;\n const parentModelName = modelNameMap.get(parentTableName) ?? parentTableName;\n const pairKey = `${childTableName}→${parentTableName}`;\n const isSelfRelation = childTableName === parentTableName;\n const needsRelationName = (fkCountByPair.get(pairKey) as number) > 1 || isSelfRelation;\n\n const isOneToOne = detectOneToOne(fk, table);\n\n const childRelFieldName = resolveUniqueFieldName(\n deriveRelationFieldName(fk.columns, parentTableName),\n childUsed,\n parentModelName,\n );\n const relationName = needsRelationName\n ? deriveRelationName(fk, childRelFieldName, parentModelName, isSelfRelation)\n : undefined;\n const childOptional = fk.columns.some(\n (columnName) => table.columns[columnName]?.nullable ?? false,\n );\n\n const childRelField = buildChildRelationField(\n childRelFieldName,\n parentModelName,\n fk,\n childOptional,\n relationName,\n table,\n );\n\n addRelationField(relationsByTable, childTableName, childRelField);\n childUsed.add(childRelFieldName);\n\n const parentUsed = usedFieldNames.get(parentTableName) ?? new Set();\n usedFieldNames.set(parentTableName, parentUsed);\n\n const backRelFieldName = resolveUniqueFieldName(\n deriveBackRelationFieldName(childModelName, isOneToOne),\n parentUsed,\n childModelName,\n );\n\n const backRelField: RelationField = {\n fieldName: backRelFieldName,\n typeName: childModelName,\n optional: isOneToOne,\n list: !isOneToOne,\n relationName,\n };\n\n addRelationField(relationsByTable, parentTableName, backRelField);\n parentUsed.add(backRelFieldName);\n }\n }\n\n return { relationsByTable };\n}\n\nfunction detectOneToOne(fk: SqlForeignKeyIR, table: SqlTableIR): boolean {\n const fkCols = [...fk.columns].sort();\n\n if (table.primaryKey) {\n const pkCols = [...table.primaryKey.columns].sort();\n if (pkCols.length === fkCols.length && pkCols.every((c, i) => c === fkCols[i])) {\n return true;\n }\n }\n\n for (const unique of table.uniques) {\n const uniqueCols = [...unique.columns].sort();\n if (uniqueCols.length === fkCols.length && uniqueCols.every((c, i) => c === fkCols[i])) {\n return true;\n }\n }\n\n for (const index of table.indexes) {\n if (!index.unique || index.partial || index.columns === undefined) {\n continue;\n }\n const indexCols = [...index.columns].sort();\n if (indexCols.length === fkCols.length && indexCols.every((c, i) => c === fkCols[i])) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction deriveRelationName(\n fk: SqlForeignKeyIR,\n childRelationFieldName: string,\n parentModelName: string,\n isSelfRelation: boolean,\n): string {\n if (fk.name) {\n return fk.name;\n }\n if (isSelfRelation) {\n return `${childRelationFieldName.charAt(0).toUpperCase() + childRelationFieldName.slice(1)}${pluralize(parentModelName)}`;\n }\n return fk.columns.join('_');\n}\n\n/**\n * Builds the child-side {@link RelationField} for a single foreign key:\n * `typeName` is the parent model name, `fields`/`references` are the FK's raw\n * columns, and `onDelete`/`onUpdate` are normalized to their PSL spelling.\n * Exported so a caller resolving a foreign key against a model outside\n * `tables` (e.g. a cross-space reference into another contract) can reuse the\n * same normalization instead of duplicating it.\n *\n * `hostTable` is the table the FK is declared on (i.e. `table`, not the\n * referenced parent) — its own indexes/uniques/primary key are what a\n * backing index for this FK would be. When none of them exactly match the\n * FK's source columns (in order), `index: false` is stamped so the emitted\n * `@relation` opts out of the framework's default derived backing-index\n * expectation, matching what `db verify` will find live. Passing the table\n * is optional so existing single-FK callers (e.g. cross-space resolution\n * before a host table reference is threaded through) can omit it and keep\n * the framework default.\n */\nexport function buildChildRelationField(\n fieldName: string,\n parentModelName: string,\n fk: SqlForeignKeyIR,\n optional: boolean,\n relationName?: string,\n hostTable?: SqlTableIR,\n): RelationField {\n const onDelete = fk.onDelete && fk.onDelete !== DEFAULT_ON_DELETE ? fk.onDelete : undefined;\n const onUpdate = fk.onUpdate && fk.onUpdate !== DEFAULT_ON_UPDATE ? fk.onUpdate : undefined;\n const index =\n hostTable &&\n !isBackedByColumnKeys(\n fk.columns,\n // Only indexes the inferrer actually emits can back the FK in the\n // emitted contract: partial indexes (and expression indexes, which\n // carry no column tuple) are not emitted yet, so\n // they must not suppress the explicit `index: false`.\n backingIndexColumnKeys({\n indexes: hostTable.indexes.filter((i) => i.where === undefined),\n uniques: hostTable.uniques,\n primaryKey: hostTable.primaryKey,\n }),\n )\n ? false\n : undefined;\n\n return {\n fieldName,\n typeName: parentModelName,\n referencedTableName: fk.referencedTable,\n optional,\n list: false,\n relationName,\n fkName: fk.name,\n fields: fk.columns,\n references: fk.referencedColumns,\n onDelete: onDelete ? REFERENTIAL_ACTION_PSL[onDelete] : undefined,\n onUpdate: onUpdate ? REFERENTIAL_ACTION_PSL[onUpdate] : undefined,\n index,\n };\n}\n\nfunction resolveUniqueFieldName(\n desired: string,\n usedNames: ReadonlySet<string>,\n fallbackSuffix: string,\n): string {\n if (!usedNames.has(desired)) {\n return desired;\n }\n\n const withSuffix = `${desired}${fallbackSuffix}`;\n if (!usedNames.has(withSuffix)) {\n return withSuffix;\n }\n\n let counter = 2;\n while (usedNames.has(`${desired}${counter}`)) {\n counter++;\n }\n return `${desired}${counter}`;\n}\n\nfunction addRelationField(\n map: Map<string, RelationField[]>,\n tableName: string,\n field: RelationField,\n): void {\n const existing = map.get(tableName);\n if (existing) {\n existing.push(field);\n } else {\n map.set(tableName, [field]);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as sqlFamilyError } from "./errors-ZGKTAYsm.mjs";
|
|
1
2
|
import { blindCast } from "@prisma-next/utils/casts";
|
|
2
3
|
import { hydrateNamespaceEntities } from "@prisma-next/framework-components/ir";
|
|
3
4
|
import { sqlContractCanonicalizationHooks } from "@prisma-next/sql-contract/canonicalization-hooks";
|
|
@@ -78,7 +79,11 @@ var SqlContractSerializerBase = class {
|
|
|
78
79
|
hydrateSqlNamespaceMap(namespaces) {
|
|
79
80
|
return Object.fromEntries(Object.entries(namespaces).map(([nsId, namespaceEntryRaw]) => {
|
|
80
81
|
const namespaceHydrated = this.hydrateSqlNamespaceEntry(nsId, namespaceEntryRaw);
|
|
81
|
-
if (!isMaterializedSqlNamespace(namespaceHydrated)) throw
|
|
82
|
+
if (!isMaterializedSqlNamespace(namespaceHydrated)) throw sqlFamilyError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Target serializer bug: hydrateSqlNamespaceEntry for namespace "${nsId}" returned a non-NamespaceBase value. Override hydrateSqlNamespaceEntry to produce a target namespace concretion.`, {
|
|
83
|
+
why: "The target contract serializer hydrated a namespace into a value that is not a materialized namespace concretion.",
|
|
84
|
+
fix: "Fix the target package: its hydrateSqlNamespaceEntry override must return a target namespace concretion.",
|
|
85
|
+
meta: { namespaceId: nsId }
|
|
86
|
+
});
|
|
82
87
|
return [nsId, namespaceHydrated];
|
|
83
88
|
}));
|
|
84
89
|
}
|
|
@@ -165,4 +170,4 @@ var SqlContractSerializer = class extends SqlContractSerializerBase {
|
|
|
165
170
|
//#endregion
|
|
166
171
|
export { SqlContractSerializerBase as n, SqlContractSerializer as t };
|
|
167
172
|
|
|
168
|
-
//# sourceMappingURL=sql-contract-serializer-
|
|
173
|
+
//# sourceMappingURL=sql-contract-serializer-othnJUZ_.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-contract-serializer-othnJUZ_.mjs","names":["isPlainRecord"],"sources":["../src/core/ir/sql-contract-serializer-base.ts","../src/core/ir/sql-contract-serializer.ts"],"sourcesContent":["import { ContractValidationError } from '@prisma-next/contract/contract-validation-error';\nimport { isPlainRecord } from '@prisma-next/contract/is-plain-record';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { ContractSerializer } from '@prisma-next/framework-components/control';\nimport {\n type AnyEntityKindDescriptor,\n hydrateNamespaceEntities,\n type Namespace,\n} from '@prisma-next/framework-components/ir';\nimport { sqlContractCanonicalizationHooks } from '@prisma-next/sql-contract/canonicalization-hooks';\nimport { composeSqlEntityKinds } from '@prisma-next/sql-contract/entity-kinds';\nimport {\n isMaterializedSqlNamespace,\n type SqlNamespaceInput,\n SqlStorage,\n type SqlStorageInput,\n type SqlStorageTypeEntry,\n} from '@prisma-next/sql-contract/types';\nimport {\n createSqlContractSchema,\n validateSqlContractFully,\n} from '@prisma-next/sql-contract/validators';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { JsonObject, JsonValue } from '@prisma-next/utils/json';\nimport { type Type, type } from 'arktype';\nimport { sqlFamilyError } from '../errors';\n\nconst NamespaceRawSchema = type({\n id: 'string',\n 'kind?': 'string',\n entries: type({\n '+': 'ignore',\n }),\n});\n\nexport type SqlEntityHydrationFactory = (entry: unknown) => unknown;\n\n/**\n * SQL family `ContractSerializer` abstract base. Carries the SQL-shared\n * deserialization pipeline:\n *\n * 1. `parseSqlContractStructure` validates the on-disk JSON envelope\n * against the SQL contract arktype schema (`validateSqlContractFully`)\n * and returns the validated flat-data shape.\n * 2. `hydrateSqlStorage` walks the validated `storage` subtree and\n * constructs the family-shared SQL Contract IR class hierarchy\n * (`SqlStorage` -> `StorageTable` -> `StorageColumn` / `PrimaryKey`\n * / …). The rest of the contract envelope is JSON-clean primitive\n * data and passes through unchanged.\n * 3. `constructTargetContract` is the target-specific extension hook;\n * defaults to identity. Targets that need to attach target-only\n * fields (e.g. target-specific derived storage fields) override it.\n *\n * Default `serializeContract` is identity over the contract — concrete\n * SQL targets ship JSON-clean class instances, so the contract value\n * can be stringified directly. The non-enumerable family-level `kind`\n * discriminator on `SqlNode` instances stays out of the persisted\n * envelope automatically. Targets that need to canonicalize on the way\n * out (key ordering, dropping computed-only fields) override\n * `serializeContract` directly.\n */\nexport abstract class SqlContractSerializerBase<TContract extends Contract<SqlStorage>>\n implements ContractSerializer<TContract>\n{\n private readonly contractSchema: Type<unknown> | undefined;\n private readonly entryKinds: ReadonlyMap<string, AnyEntityKindDescriptor>;\n\n constructor(\n protected readonly entityHydrationRegistry: ReadonlyMap<\n string,\n SqlEntityHydrationFactory\n > = new Map(),\n packEntityKinds: readonly AnyEntityKindDescriptor[] = [],\n ) {\n this.entryKinds = composeSqlEntityKinds(packEntityKinds);\n this.contractSchema =\n packEntityKinds.length > 0 ? createSqlContractSchema(this.entryKinds) : undefined;\n }\n\n deserializeContract<T extends TContract = TContract>(json: unknown): T {\n const validated = this.parseSqlContractStructure(json);\n const hydrated = this.hydrateSqlStorage(validated);\n return this.constructTargetContract(hydrated) as T;\n }\n\n serializeContract(contract: TContract): JsonObject {\n return contract as unknown as JsonObject;\n }\n\n shouldPreserveEmpty = sqlContractCanonicalizationHooks.shouldPreserveEmpty;\n\n sortStorage = sqlContractCanonicalizationHooks.sortStorage;\n\n protected parseSqlContractStructure(json: unknown): Contract<SqlStorage> {\n return validateSqlContractFully<Contract<SqlStorage>>(\n json,\n this.contractSchema !== undefined ? { contractSchema: this.contractSchema } : undefined,\n );\n }\n\n protected hydrateSqlStorage(validated: Contract<SqlStorage>): Contract<SqlStorage> {\n const types = validated.storage.types;\n const hydratedTypes =\n types !== undefined\n ? Object.fromEntries(\n Object.entries(types).map(([name, entry]) => [\n name,\n this.hydrateStorageTypeEntry(entry),\n ]),\n )\n : undefined;\n\n const rawNamespaces = validated.storage.namespaces;\n if (rawNamespaces === undefined) {\n throw new ContractValidationError(\n 'Contract storage.namespaces is required after structural validation',\n 'structural',\n );\n }\n const hydratedNamespaces = this.hydrateSqlNamespaceMap(\n blindCast<\n Readonly<Record<string, Record<string, unknown>>>,\n 'parseSqlContractStructure validated raw JSON; namespace entries are plain objects, not SqlNamespace instances.'\n >(rawNamespaces),\n );\n\n return {\n ...validated,\n storage: new SqlStorage({\n storageHash: validated.storage.storageHash,\n ...ifDefined('types', hydratedTypes),\n namespaces: blindCast<\n SqlStorageInput['namespaces'],\n 'hydrateSqlNamespaceMap builds each namespace through the target serializer override, so every value is a SqlNamespace; the framework return type only promises the base Namespace.'\n >(hydratedNamespaces),\n }),\n };\n }\n\n protected hydrateSqlNamespaceMap(\n namespaces: Readonly<Record<string, Record<string, unknown>>>,\n ): Readonly<Record<string, Namespace>> {\n return Object.fromEntries(\n Object.entries(namespaces).map(([nsId, namespaceEntryRaw]) => {\n const namespaceHydrated = this.hydrateSqlNamespaceEntry(nsId, namespaceEntryRaw);\n if (!isMaterializedSqlNamespace(namespaceHydrated)) {\n throw sqlFamilyError(\n 'CONTRACT.PACK_CONTRIBUTION_INVALID',\n `Target serializer bug: hydrateSqlNamespaceEntry for namespace \"${nsId}\" returned a non-NamespaceBase value. Override hydrateSqlNamespaceEntry to produce a target namespace concretion.`,\n {\n why: 'The target contract serializer hydrated a namespace into a value that is not a materialized namespace concretion.',\n fix: 'Fix the target package: its hydrateSqlNamespaceEntry override must return a target namespace concretion.',\n meta: { namespaceId: nsId },\n },\n );\n }\n return [nsId, namespaceHydrated];\n }),\n );\n }\n\n protected hydrateSqlNamespaceEntry(\n nsId: string,\n raw: Record<string, unknown>,\n ): Namespace | SqlNamespaceInput {\n const id = typeof raw['id'] === 'string' ? raw['id'] : nsId;\n const parsed = NamespaceRawSchema({ ...raw, id });\n if (parsed instanceof type.errors) {\n const messages = parsed.map((p: { message: string }) => p.message).join('; ');\n throw new ContractValidationError(`Namespace hydration failed: ${messages}`, 'structural');\n }\n const entriesRaw = parsed.entries;\n const rawEntriesMap = isPlainRecord(entriesRaw) ? entriesRaw : {};\n\n const entriesInput: Record<string, Readonly<Record<string, unknown>>> = {};\n for (const [key, innerMap] of Object.entries(rawEntriesMap)) {\n entriesInput[key] = isPlainRecord(innerMap) ? innerMap : Object.freeze({});\n }\n\n const entriesOutput = hydrateNamespaceEntities(entriesInput, this.entryKinds, 'fail', id);\n\n // Always ensure a 'table' key is present (may be empty).\n if (!Object.hasOwn(entriesOutput, 'table')) {\n entriesOutput['table'] = {};\n }\n\n return blindCast<\n SqlNamespaceInput,\n 'entriesOutput holds the hydrated SQL entity-kind maps (table always present); this wraps them as the SqlNamespaceInput the target createNamespace consumes.'\n >({\n id,\n entries: entriesOutput,\n });\n }\n\n protected hydrateStorageTypeEntry(entry: SqlStorageTypeEntry): SqlStorageTypeEntry {\n if (typeof entry !== 'object' || entry === null) {\n return entry;\n }\n const kind = (entry as { kind?: unknown }).kind;\n if (typeof kind !== 'string') {\n return entry;\n }\n const factory = this.entityHydrationRegistry.get(kind);\n if (factory === undefined) {\n return entry;\n }\n return blindCast<\n SqlStorageTypeEntry,\n 'entity registry factory returns SqlStorageTypeEntry for storage.types entries'\n >(factory(entry));\n }\n\n protected constructTargetContract(hydrated: Contract<SqlStorage>): TContract {\n return hydrated as TContract;\n }\n\n /**\n * Serializes a namespace's `entries` dict by walking every enumerable\n * kind — no kind is named here, mirroring the generic hydrate walk in\n * `hydrateSqlNamespaceEntry` above. `table` is the SQL family's one\n * universal base kind (every namespace carries it), so it is always\n * emitted, even when empty; every other kind — target- or\n * pack-contributed — is emitted only when it holds at least one entry.\n * A kind carried non-enumerable on `entries` is excluded here for free,\n * since `Object.entries` honors enumerability.\n */\n protected serializeNamespaceEntries(\n entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>,\n ): Record<string, Record<string, JsonObject>> {\n const out: Record<string, Record<string, JsonObject>> = {\n table: this.serializeEntries(entries['table'] ?? {}),\n };\n for (const [kind, record] of Object.entries(entries)) {\n if (kind === 'table' || record == null || Object.keys(record).length === 0) {\n continue;\n }\n out[kind] = this.serializeEntries(record);\n }\n return out;\n }\n\n private serializeEntries(entries: Readonly<Record<string, unknown>>): Record<string, JsonObject> {\n const out: Record<string, JsonObject> = {};\n for (const [name, entry] of Object.entries(entries)) {\n out[name] = this.serializeJsonObject(entry);\n }\n return out;\n }\n\n protected serializeJsonObject(value: unknown): JsonObject {\n return blindCast<\n JsonObject,\n 'serializeJsonValue round-trips an IR node through JSON, yielding a JsonObject'\n >(this.serializeJsonValue(value));\n }\n\n private serializeJsonValue(value: unknown): JsonValue {\n return blindCast<JsonValue, 'JSON.parse(JSON.stringify(x)) yields a JsonValue'>(\n JSON.parse(JSON.stringify(value)),\n );\n }\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { SqlContractSerializerBase } from './sql-contract-serializer-base';\n\n/**\n * Default SQL family `ContractSerializer` concretion. Inherits the\n * full SQL-shared deserialization pipeline (structural validation +\n * IR-class hydration) without pack-registered `storage.types`\n * hydration factories — targets that emit polymorphic JSON outside the\n * codec-typed envelope wire a target-specific subclass with a populated\n * registry (see Postgres). Family-level call sites instantiate this\n * default directly when no target serializer is supplied.\n *\n * Because this serializer has no target concretion, deserialization of\n * contracts that include namespace entries from JSON will throw unless\n * the caller provides pre-hydrated `NamespaceBase` instances. Production\n * paths always supply a target-specific serializer.\n */\nexport class SqlContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {\n constructor() {\n super(new Map());\n }\n}\n"],"mappings":"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"}
|
|
@@ -274,9 +274,9 @@ interface SqlMigrationPlannerPlanOptions {
|
|
|
274
274
|
* or `null` for reconciliation flows that have no prior contract.
|
|
275
275
|
*
|
|
276
276
|
* Required at every call site so the structural fact "I have a prior
|
|
277
|
-
* contract / I don't" is visible in the type. `migration plan` reads
|
|
278
|
-
*
|
|
279
|
-
* the parsed value; `db update` / `db init` reconcile against the
|
|
277
|
+
* contract / I don't" is visible in the type. `migration plan` reads the
|
|
278
|
+
* predecessor's contract from the snapshot store by its storage hash and
|
|
279
|
+
* passes the parsed value; `db update` / `db init` reconcile against the
|
|
280
280
|
* live schema and pass `null`. Strategies that
|
|
281
281
|
* need from/to column-shape comparisons (unsafe type change, nullability
|
|
282
282
|
* tightening) use this to decide whether to emit `dataTransform`
|
|
@@ -286,6 +286,13 @@ interface SqlMigrationPlannerPlanOptions {
|
|
|
286
286
|
* plan's `describe()` as `fromContract?.storage.storageHash ?? null`.
|
|
287
287
|
*/
|
|
288
288
|
readonly fromContract: Contract<SqlStorage> | null;
|
|
289
|
+
/**
|
|
290
|
+
* POSIX-relative path from the migration package dir to
|
|
291
|
+
* `migrations/snapshots`, e.g. `'../../snapshots'`. Threaded straight
|
|
292
|
+
* into the produced plan's `renderTypeScript()` metadata so the
|
|
293
|
+
* scaffold's contract-snapshot imports point at the deduplicated store.
|
|
294
|
+
*/
|
|
295
|
+
readonly snapshotsImportPath: string;
|
|
289
296
|
/**
|
|
290
297
|
* Active framework components participating in this composition.
|
|
291
298
|
* Each component is target-bound so SQL targets can dispatch
|
|
@@ -410,4 +417,4 @@ interface CreateSqlMigrationPlanOptions<TTargetDetails> {
|
|
|
410
417
|
}
|
|
411
418
|
//#endregion
|
|
412
419
|
export { SqlPlannerSuccessResult as A, SqlMigrationRunnerSuccessValue as C, SqlPlannerConflictLocation as D, SqlPlannerConflictKind as E, SqlPlannerFailureResult as O, SqlMigrationRunnerResult as S, SqlPlannerConflict as T, SqlMigrationRunner as _, FieldEvent as a, SqlMigrationRunnerExecuteOptions as b, SqlControlAdapterDescriptor as c, SqlMigrationPlanContractInfo as d, SqlMigrationPlanOperation as f, SqlMigrationPlannerPlanOptions as g, SqlMigrationPlanner as h, ExpandNativeTypeInput as i, StorageTypePlanResult as j, SqlPlannerResult as k, SqlControlExtensionDescriptor as l, SqlMigrationPlanOperationTarget as m, CodecControlHooks as n, FieldEventContext as o, SqlMigrationPlanOperationStep as p, CreateSqlMigrationPlanOptions as r, ResolveIdentityValueInput as s, AnyRecord as t, SqlMigrationPlan as u, SqlMigrationRunnerErrorCode as v, SqlPlanTargetDetails as w, SqlMigrationRunnerFailure as x, SqlMigrationRunnerExecuteCallbacks as y };
|
|
413
|
-
//# sourceMappingURL=types-
|
|
420
|
+
//# sourceMappingURL=types-DhAmOoxA.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-
|
|
1
|
+
{"version":3,"file":"types-DhAmOoxA.d.mts","names":[],"sources":["../src/core/migrations/types.ts"],"mappings":";;;;;;;;;;KAkCY,YAAY,SAAS;UAEhB,sBAAsB;WAC5B,qBAAqB,0BAA0B;;;;;UAMzC;WACN;WACA;WACA,aAAa;;;;;;;;;UAUP;WACN;WACA;WACA,aAAa;;;;;;;;;;;;;;;;KAiBZ;;;;;;;;;;;;;UAcK;WACN;WACA;WACA;WACA,aAAa;WACb,WAAW;WACX,aAAa;WACb,WAAW;;UAGL,kBAAkB;;;;;;;;;EASjC,sBAAsB;aACX;aACA,cAAc;aACd,UAAU,SAAS;aACnB,QAAQ;aACR;aACA,QAAQ;QACb,sBAAsB;EAC5B,cAAc;aACH;aACA,cAAc;aACd,QAAQ;aACR;iBACI;EACf,mBAAmB;aACR,QAAQ;aACR;QACL,QAAQ,eAAe;;;;;;;;;;;EAW7B,oBAAoB,OAAO;;;;;;;;;;EAU3B,wBAAwB,OAAO;;;;;;;;;;;;;;;EAe/B,gBAAgB,OAAO,YAAY,KAAK,+BAA+B;;UAGxD,8BAA8B,kCACrC,kCAAkC;WACjC,wBAAwB;;;;;;;;;;;;WAYxB,gBAAgB,cAAc,SAAS;;UAGjC,4BAA4B,kCACnC,gCAAgC,WAAW,kBAAkB;WAC5D,wBAAwB;;UAGlB;WACN;WACA;;;;;;;;;WASA;WACA,OAAO;;;;;;;;;UAUD;WACN;WACA;;UAGM,gCAAgC;WACtC;WACA,UAAU;;UAGJ,0BAA0B,wBAAwB;WACxD;WACA,QAAQ,gCAAgC;WACxC,mBAAmB;WACnB,kBAAkB;WAClB,oBAAoB;WACpB,OAAO;;UAGD;WACN;WACA;;UAGM,iBAAiB,wBAAwB;;;;;;;;;;;;;;;WAe/C;;;;;WAKA,SAAS;;;;WAIT,aAAa;WACb,sBACL,0BAA0B,kBAC1B,QAAQ,0BAA0B;;;;;;;;;WAU7B;WACA,OAAO;;KAGN;UASK;WACN;WACA;WACA;WACA;WACA;WACA;;UAGM,2BAA2B;WACjC,MAAM;WACN,WAAW;WACX,OAAO;;UAGD,wBAAwB,wBAC/B,KAAK;WACJ;WACA,MAAM,iBAAiB;;UAGjB,gCAAgC,KAAK;WAC3C;WACA,oBAAoB;;KAGnB,iBAAiB,kBACzB,wBAAwB,kBACxB;UAEa;WACN,UAAU,SAAS;;;;;;WAMnB,QAAQ;WACR,QAAQ;WACR;;;;;;;;WAQA;;;;;;;;;;;;;;;;;WAiBA,cAAc,SAAS;;;;;;;WAOvB;;;;;;;WAOA,qBAAqB,cAAc;;;;;;;;;;WAUnC,YAAY;;UAGN,oBAAoB;EACnC,KAAK,SAAS,iCAAiC,iBAAiB;;UAGjD,mCAAmC;EAClD,kBAAkB,WAAW,0BAA0B;EACvD,qBAAqB,WAAW,0BAA0B;;UAG3C,iCAAiC;WACvC,MAAM,iBAAiB;WACvB,QAAQ;;;;;;;;WAQR;;;;;WAKA,qBAAqB,SAAS;;;;;WAK9B,QAAQ;WACR;WACA;WACA,YAAY,mCAAmC;WAC/C,UAAU;;;;;WAKV,kBAAkB;;;;;;;WAOlB,qBAAqB,cAAc;;;;;WAKnC,yBAAyB;;KAGxB;UAYK,kCAAkC;WACxC,MAAM;WACN,OAAO;;UAGD,uCAAuC;KAE5C,2BAA2B,OACrC,gCACA;UAGe,mBAAmB;;;;;;;;;;;;;;EAclC,QAAQ;aACG,QAAQ;aACR,iBAAiB,cAAc,iCAAiC;MACvE,QAAQ;;;;;;;;;;;EAYZ,oBACE,SAAS,iCAAiC,kBACzC,QAAQ;;UAGI,8BAA8B;WACpC;;;;WAIA;WACA,SAAS;WACT,aAAa;WACb,qBAAqB,0BAA0B;;;;;;WAM/C;WACA,OAAO"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as sqlFamilyError } from "./errors-ZGKTAYsm.mjs";
|
|
1
2
|
import { type } from "arktype";
|
|
2
3
|
//#region src/core/verify.ts
|
|
3
4
|
const MetaSchema = type({ "[string]": "unknown" });
|
|
@@ -46,7 +47,11 @@ function parseContractMarkerRow(row) {
|
|
|
46
47
|
const result = ContractMarkerRowSchema(row);
|
|
47
48
|
if (result instanceof type.errors) {
|
|
48
49
|
const messages = result.map((p) => p.message).join("; ");
|
|
49
|
-
throw
|
|
50
|
+
throw sqlFamilyError("CONTRACT.MARKER_ROW_CORRUPT", `Invalid contract marker row: ${messages}`, {
|
|
51
|
+
why: "The contract marker row read from the database does not match the expected marker shape.",
|
|
52
|
+
fix: "Re-sign the database with `prisma-next db sign`, or repair the marker table.",
|
|
53
|
+
meta: { issues: messages }
|
|
54
|
+
});
|
|
50
55
|
}
|
|
51
56
|
const updatedAt = result.updated_at ? result.updated_at instanceof Date ? result.updated_at : new Date(result.updated_at) : /* @__PURE__ */ new Date();
|
|
52
57
|
return {
|
|
@@ -78,4 +83,4 @@ function collectSupportedCodecTypeIds(descriptors) {
|
|
|
78
83
|
//#endregion
|
|
79
84
|
export { parseContractMarkerRow as n, collectSupportedCodecTypeIds as t };
|
|
80
85
|
|
|
81
|
-
//# sourceMappingURL=verify-
|
|
86
|
+
//# sourceMappingURL=verify-DuuJFiTm.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-DuuJFiTm.mjs","names":[],"sources":["../src/core/verify.ts"],"sourcesContent":["import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport { type } from 'arktype';\nimport { sqlFamilyError } from './errors';\n\nconst MetaSchema = type({ '[string]': 'unknown' });\n\nfunction parseMeta(meta: unknown): Record<string, unknown> {\n if (meta === null || meta === undefined) {\n return {};\n }\n\n let parsed: unknown;\n if (typeof meta === 'string') {\n try {\n parsed = JSON.parse(meta);\n } catch {\n return {};\n }\n } else {\n parsed = meta;\n }\n\n const result = MetaSchema(parsed);\n if (result instanceof type.errors) {\n return {};\n }\n\n return result as Record<string, unknown>;\n}\n\n/**\n * SQLite stores `contract_json` as TEXT, so the wire shape is a JSON string;\n * Postgres uses `jsonb` and returns an already-parsed value. Normalize both\n * here so `ContractMarkerRecord.contractJson` is always the structured form.\n */\nfunction parseContractJson(value: unknown): unknown {\n if (value === null || value === undefined) return null;\n if (typeof value !== 'string') return value;\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n}\n\n/**\n * Wire shape of a `prisma_contract.marker` row as it comes out of a SQL\n * driver. Snake-cased to match the on-disk column names. Shared by every\n * SQL target's `readMarker` so each runner doesn't redeclare it inline.\n */\nexport type ContractMarkerRow = {\n core_hash: string;\n profile_hash: string;\n contract_json: unknown | null;\n canonical_version: number | null;\n updated_at: Date | string;\n app_tag: string | null;\n meta: unknown | null;\n // SQLite stores arrays as JSON-TEXT, so this is `string` on the wire from\n // a SQLite driver and `string[]` from a Postgres driver. Targets normalize\n // before passing to `parseContractMarkerRow`.\n invariants: unknown;\n};\n\nconst ContractMarkerRowSchema = type({\n core_hash: 'string',\n profile_hash: 'string',\n 'contract_json?': 'unknown | null',\n 'canonical_version?': 'number | null',\n 'updated_at?': 'Date | string',\n 'app_tag?': 'string | null',\n 'meta?': 'unknown | null',\n invariants: type('string').array(),\n});\n\n/**\n * Parses a contract marker row from database query result.\n * This is SQL-specific parsing logic (handles SQL row structure with snake_case columns).\n */\nexport function parseContractMarkerRow(row: unknown): ContractMarkerRecord {\n const result = ContractMarkerRowSchema(row);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw sqlFamilyError(\n 'CONTRACT.MARKER_ROW_CORRUPT',\n `Invalid contract marker row: ${messages}`,\n {\n why: 'The contract marker row read from the database does not match the expected marker shape.',\n fix: 'Re-sign the database with `prisma-next db sign`, or repair the marker table.',\n meta: { issues: messages },\n },\n );\n }\n\n const updatedAt = result.updated_at\n ? result.updated_at instanceof Date\n ? result.updated_at\n : new Date(result.updated_at)\n : new Date();\n\n return {\n storageHash: result.core_hash,\n profileHash: result.profile_hash,\n contractJson: parseContractJson(result.contract_json),\n canonicalVersion: result.canonical_version ?? null,\n updatedAt,\n appTag: result.app_tag ?? null,\n meta: parseMeta(result.meta),\n invariants: result.invariants,\n };\n}\n\n/**\n * Collects supported codec type IDs from adapter and extension manifests.\n * Returns a sorted, unique array of type IDs that are declared in the manifests.\n * This enables coverage checks by comparing contract column types against supported types.\n *\n * Note: This extracts type IDs from manifest type imports, not from runtime codec registries.\n * The manifests declare which codec types are available, but the actual type IDs\n * are defined in the codec-types TypeScript modules that are imported.\n *\n * For MVP, we return an empty array since extracting type IDs from TypeScript modules\n * would require runtime evaluation or static analysis. This can be enhanced later.\n */\nexport function collectSupportedCodecTypeIds(\n descriptors: ReadonlyArray<{ readonly id: string }>,\n): readonly string[] {\n // For MVP, return empty array\n // Future enhancement: Extract type IDs from codec-types modules via static analysis\n // or require manifests to explicitly list supported type IDs\n void descriptors;\n return [];\n}\n"],"mappings":";;;AAIA,MAAM,aAAa,KAAK,EAAE,YAAY,UAAU,CAAC;AAEjD,SAAS,UAAU,MAAwC;CACzD,IAAI,SAAS,QAAQ,SAAS,KAAA,GAC5B,OAAO,CAAC;CAGV,IAAI;CACJ,IAAI,OAAO,SAAS,UAClB,IAAI;EACF,SAAS,KAAK,MAAM,IAAI;CAC1B,QAAQ;EACN,OAAO,CAAC;CACV;MAEA,SAAS;CAGX,MAAM,SAAS,WAAW,MAAM;CAChC,IAAI,kBAAkB,KAAK,QACzB,OAAO,CAAC;CAGV,OAAO;AACT;;;;;;AAOA,SAAS,kBAAkB,OAAyB;CAClD,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW,OAAO;CAClD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI;EACF,OAAO,KAAK,MAAM,KAAK;CACzB,QAAQ;EACN,OAAO;CACT;AACF;AAqBA,MAAM,0BAA0B,KAAK;CACnC,WAAW;CACX,cAAc;CACd,kBAAkB;CAClB,sBAAsB;CACtB,eAAe;CACf,YAAY;CACZ,SAAS;CACT,YAAY,KAAK,QAAQ,CAAC,CAAC,MAAM;AACnC,CAAC;;;;;AAMD,SAAgB,uBAAuB,KAAoC;CACzE,MAAM,SAAS,wBAAwB,GAAG;CAC1C,IAAI,kBAAkB,KAAK,QAAQ;EACjC,MAAM,WAAW,OAAO,KAAK,MAA2B,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI;EAC5E,MAAM,eACJ,+BACA,gCAAgC,YAChC;GACE,KAAK;GACL,KAAK;GACL,MAAM,EAAE,QAAQ,SAAS;EAC3B,CACF;CACF;CAEA,MAAM,YAAY,OAAO,aACrB,OAAO,sBAAsB,OAC3B,OAAO,aACP,IAAI,KAAK,OAAO,UAAU,oBAC5B,IAAI,KAAK;CAEb,OAAO;EACL,aAAa,OAAO;EACpB,aAAa,OAAO;EACpB,cAAc,kBAAkB,OAAO,aAAa;EACpD,kBAAkB,OAAO,qBAAqB;EAC9C;EACA,QAAQ,OAAO,WAAW;EAC1B,MAAM,UAAU,OAAO,IAAI;EAC3B,YAAY,OAAO;CACrB;AACF;;;;;;;;;;;;;AAcA,SAAgB,6BACd,aACmB;CAKnB,OAAO,CAAC;AACV"}
|
package/dist/verify.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.mts","names":[],"sources":["../src/core/verify.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"verify.d.mts","names":[],"sources":["../src/core/verify.ts"],"mappings":";;;;;;;KAkDY;EACV;EACA;EACA;EACA;EACA,YAAY;EACZ;EACA;EAIA;;;;;;iBAkBc,uBAAuB,eAAe"}
|
package/dist/verify.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as parseContractMarkerRow } from "./verify-
|
|
1
|
+
import { n as parseContractMarkerRow } from "./verify-DuuJFiTm.mjs";
|
|
2
2
|
export { parseContractMarkerRow };
|
package/package.json
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/family-sql",
|
|
3
|
-
"version": "0.16.0-dev.
|
|
3
|
+
"version": "0.16.0-dev.31",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "SQL family descriptor for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/contract": "0.16.0-dev.
|
|
10
|
-
"@prisma-next/emitter": "0.16.0-dev.
|
|
11
|
-
"@prisma-next/framework-components": "0.16.0-dev.
|
|
12
|
-
"@prisma-next/migration-tools": "0.16.0-dev.
|
|
13
|
-
"@prisma-next/operations": "0.16.0-dev.
|
|
14
|
-
"@prisma-next/sql-contract": "0.16.0-dev.
|
|
15
|
-
"@prisma-next/sql-contract-emitter": "0.16.0-dev.
|
|
16
|
-
"@prisma-next/sql-contract-ts": "0.16.0-dev.
|
|
17
|
-
"@prisma-next/sql-operations": "0.16.0-dev.
|
|
18
|
-
"@prisma-next/sql-relational-core": "0.16.0-dev.
|
|
19
|
-
"@prisma-next/sql-runtime": "0.16.0-dev.
|
|
20
|
-
"@prisma-next/sql-schema-ir": "0.16.0-dev.
|
|
21
|
-
"@prisma-next/utils": "0.16.0-dev.
|
|
9
|
+
"@prisma-next/contract": "0.16.0-dev.31",
|
|
10
|
+
"@prisma-next/emitter": "0.16.0-dev.31",
|
|
11
|
+
"@prisma-next/framework-components": "0.16.0-dev.31",
|
|
12
|
+
"@prisma-next/migration-tools": "0.16.0-dev.31",
|
|
13
|
+
"@prisma-next/operations": "0.16.0-dev.31",
|
|
14
|
+
"@prisma-next/sql-contract": "0.16.0-dev.31",
|
|
15
|
+
"@prisma-next/sql-contract-emitter": "0.16.0-dev.31",
|
|
16
|
+
"@prisma-next/sql-contract-ts": "0.16.0-dev.31",
|
|
17
|
+
"@prisma-next/sql-operations": "0.16.0-dev.31",
|
|
18
|
+
"@prisma-next/sql-relational-core": "0.16.0-dev.31",
|
|
19
|
+
"@prisma-next/sql-runtime": "0.16.0-dev.31",
|
|
20
|
+
"@prisma-next/sql-schema-ir": "0.16.0-dev.31",
|
|
21
|
+
"@prisma-next/utils": "0.16.0-dev.31",
|
|
22
22
|
"arktype": "^2.2.2",
|
|
23
23
|
"pluralize": "^8.0.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@prisma-next/driver-postgres": "0.16.0-dev.
|
|
27
|
-
"@prisma-next/psl-parser": "0.16.0-dev.
|
|
28
|
-
"@prisma-next/psl-printer": "0.16.0-dev.
|
|
29
|
-
"@prisma-next/sql-contract-psl": "0.16.0-dev.
|
|
30
|
-
"@prisma-next/test-utils": "0.16.0-dev.
|
|
31
|
-
"@prisma-next/tsconfig": "0.16.0-dev.
|
|
32
|
-
"@prisma-next/tsdown": "0.16.0-dev.
|
|
26
|
+
"@prisma-next/driver-postgres": "0.16.0-dev.31",
|
|
27
|
+
"@prisma-next/psl-parser": "0.16.0-dev.31",
|
|
28
|
+
"@prisma-next/psl-printer": "0.16.0-dev.31",
|
|
29
|
+
"@prisma-next/sql-contract-psl": "0.16.0-dev.31",
|
|
30
|
+
"@prisma-next/test-utils": "0.16.0-dev.31",
|
|
31
|
+
"@prisma-next/tsconfig": "0.16.0-dev.31",
|
|
32
|
+
"@prisma-next/tsdown": "0.16.0-dev.31",
|
|
33
33
|
"@types/pluralize": "^0.0.33",
|
|
34
34
|
"tsdown": "0.22.8",
|
|
35
35
|
"typescript": "5.9.3",
|