@prisma-next/family-sql 0.14.0-dev.43 → 0.14.0-dev.45
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/control.d.mts +208 -6
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +5 -1
- package/dist/control.mjs.map +1 -1
- package/dist/diff.d.mts +1 -1
- package/dist/migration.d.mts +1 -1
- package/dist/psl-infer.d.mts +23 -2
- package/dist/psl-infer.d.mts.map +1 -1
- package/dist/psl-infer.mjs +9 -1
- package/dist/psl-infer.mjs.map +1 -1
- package/dist/{types-CkOIJXxU.d.mts → types-DBxrwN1d.d.mts} +4 -185
- package/dist/types-DBxrwN1d.d.mts.map +1 -0
- package/package.json +21 -21
- package/src/core/control-instance.ts +18 -2
- package/src/core/control-target-descriptor.ts +83 -0
- package/src/core/migrations/types.ts +0 -53
- package/src/core/psl-contract-infer/printer-config.ts +12 -0
- package/src/core/psl-contract-infer/relation-inference.ts +9 -1
- package/src/exports/control.ts +4 -1
- package/src/exports/psl-infer.ts +4 -1
- package/dist/types-CkOIJXxU.d.mts.map +0 -1
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","const 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\nexport function pluralize(word: string): string {\n if (\n word.endsWith('s') ||\n word.endsWith('x') ||\n word.endsWith('z') ||\n word.endsWith('ch') ||\n word.endsWith('sh')\n ) {\n return `${word}es`;\n }\n if (word.endsWith('y') && !/[aeiou]y$/i.test(word)) {\n return `${word.slice(0, -1)}ies`;\n }\n return `${word}s`;\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 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 );\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\nfunction buildChildRelationField(\n fieldName: string,\n parentModelName: string,\n fk: SqlForeignKeyIR,\n optional: boolean,\n relationName?: string,\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\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 };\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","const 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\nexport function pluralize(word: string): string {\n if (\n word.endsWith('s') ||\n word.endsWith('x') ||\n word.endsWith('z') ||\n word.endsWith('ch') ||\n word.endsWith('sh')\n ) {\n return `${word}es`;\n }\n if (word.endsWith('y') && !/[aeiou]y$/i.test(word)) {\n return `${word.slice(0, -1)}ies`;\n }\n return `${word}s`;\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 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 );\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 */\nexport function buildChildRelationField(\n fieldName: string,\n parentModelName: string,\n fk: SqlForeignKeyIR,\n optional: boolean,\n relationName?: string,\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\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 };\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,152 +1,13 @@
|
|
|
1
1
|
import { r as SqlControlAdapter } from "./control-adapter-DHYFuOBy.mjs";
|
|
2
|
-
import { Contract
|
|
3
|
-
import {
|
|
2
|
+
import { Contract } from "@prisma-next/contract/types";
|
|
3
|
+
import { ContractSpace, ControlAdapterDescriptor, ControlExtensionDescriptor, DiffIssue, MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlannerConflict, MigrationPlannerFailureResult, MigrationPlannerSuccessResult, MigrationRunnerExecutionChecks, MigrationRunnerFailure, MigrationRunnerPerSpaceSuccessValue, MigrationRunnerResult, OpFactoryCall, OperationContext, SchemaIssue } from "@prisma-next/framework-components/control";
|
|
4
4
|
import { SqlControlDriverInstance, SqlStorage, StorageColumn, StorageTable, StorageTypeInstance } from "@prisma-next/sql-contract/types";
|
|
5
5
|
import { Result } from "@prisma-next/utils/result";
|
|
6
|
-
import { AnyQueryAst, DdlNode, LowererContext, SqlExecuteRequest } from "@prisma-next/sql-relational-core/ast";
|
|
7
6
|
import { SqlSchemaIR, SqlSchemaIRNode } from "@prisma-next/sql-schema-ir/types";
|
|
8
7
|
import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
|
|
9
|
-
import { TypesImportSpec } from "@prisma-next/framework-components/emission";
|
|
10
|
-
import { PslDocumentAst } from "@prisma-next/framework-components/psl-ast";
|
|
11
8
|
import { AggregateMigrationEdgeRef } from "@prisma-next/migration-tools/aggregate";
|
|
12
9
|
import { SqlOperationDescriptors } from "@prisma-next/sql-operations";
|
|
13
10
|
|
|
14
|
-
//#region src/core/control-instance.d.ts
|
|
15
|
-
interface SqlTypeMetadata {
|
|
16
|
-
readonly typeId: string;
|
|
17
|
-
readonly familyId: 'sql';
|
|
18
|
-
readonly targetId: string;
|
|
19
|
-
readonly nativeType?: string;
|
|
20
|
-
}
|
|
21
|
-
type SqlTypeMetadataRegistry = Map<string, SqlTypeMetadata>;
|
|
22
|
-
interface SqlFamilyInstanceState {
|
|
23
|
-
readonly codecTypeImports: ReadonlyArray<TypesImportSpec>;
|
|
24
|
-
readonly extensionIds: ReadonlyArray<string>;
|
|
25
|
-
readonly typeMetadataRegistry: SqlTypeMetadataRegistry;
|
|
26
|
-
}
|
|
27
|
-
interface SqlControlFamilyInstance extends ControlFamilyInstance<'sql', SqlSchemaIRNode>, SchemaViewCapable<SqlSchemaIRNode>, PslContractInferCapable<SqlSchemaIRNode>, OperationPreviewCapable, SqlFamilyInstanceState {
|
|
28
|
-
/**
|
|
29
|
-
* The family seam-of-record for on-disk contract reads. Structurally
|
|
30
|
-
* validates the JSON envelope, then hydrates IR-class instances via
|
|
31
|
-
* the per-target ContractSerializer. The single named entry point
|
|
32
|
-
* every CLI on-disk read crosses (TML-2536) — `as Contract` casts
|
|
33
|
-
* in production package sources are a serializer-bypass smell guarded
|
|
34
|
-
* by `pnpm lint:no-contract-cast`.
|
|
35
|
-
*/
|
|
36
|
-
deserializeContract(contractJson: unknown): Contract;
|
|
37
|
-
verify(options: {
|
|
38
|
-
readonly driver: SqlControlDriverInstance<string>;
|
|
39
|
-
readonly contract: unknown;
|
|
40
|
-
readonly expectedTargetId: string;
|
|
41
|
-
readonly contractPath: string;
|
|
42
|
-
readonly configPath?: string;
|
|
43
|
-
}): Promise<VerifyDatabaseResult>;
|
|
44
|
-
/**
|
|
45
|
-
* Verify a contract against an already-introspected schema.
|
|
46
|
-
*
|
|
47
|
-
* Callers that need to verify against the live database compose
|
|
48
|
-
* `introspect({ driver })` + `verifySchema({ contract, schema, ... })`.
|
|
49
|
-
* The aggregate verifier hands in the full introspected schema and scopes
|
|
50
|
-
* the returned result to each member's contract space afterwards — so
|
|
51
|
-
* sibling-space tables never survive as `extras`.
|
|
52
|
-
*/
|
|
53
|
-
verifySchema(options: {
|
|
54
|
-
readonly contract: unknown;
|
|
55
|
-
readonly schema: SqlSchemaIRNode;
|
|
56
|
-
readonly strict: boolean;
|
|
57
|
-
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
|
|
58
|
-
}): VerifyDatabaseSchemaResult;
|
|
59
|
-
sign(options: {
|
|
60
|
-
readonly driver: SqlControlDriverInstance<string>;
|
|
61
|
-
readonly contract: unknown;
|
|
62
|
-
readonly contractPath: string;
|
|
63
|
-
readonly configPath?: string;
|
|
64
|
-
}): Promise<SignDatabaseResult>;
|
|
65
|
-
introspect(options: {
|
|
66
|
-
readonly driver: SqlControlDriverInstance<string>;
|
|
67
|
-
readonly contract?: unknown;
|
|
68
|
-
}): Promise<SqlSchemaIRNode>;
|
|
69
|
-
inferPslContract(schemaIR: SqlSchemaIRNode): PslDocumentAst;
|
|
70
|
-
lowerAst(ast: AnyQueryAst | DdlNode, context: LowererContext<unknown>): Promise<SqlExecuteRequest>;
|
|
71
|
-
/**
|
|
72
|
-
* Inserts the initial marker row for `space` (upsert on `space`).
|
|
73
|
-
* Delegates to the target control adapter's write SPI; see
|
|
74
|
-
* `SqlControlAdapter.initMarker`.
|
|
75
|
-
*/
|
|
76
|
-
initMarker(options: {
|
|
77
|
-
readonly driver: SqlControlDriverInstance<string>;
|
|
78
|
-
readonly space: string;
|
|
79
|
-
readonly destination: {
|
|
80
|
-
readonly storageHash: string;
|
|
81
|
-
readonly profileHash: string;
|
|
82
|
-
readonly invariants?: readonly string[];
|
|
83
|
-
};
|
|
84
|
-
}): Promise<void>;
|
|
85
|
-
/**
|
|
86
|
-
* Compare-and-swap advance of the marker row for `space`. Returns `true`
|
|
87
|
-
* when the swap matched a row; see `SqlControlAdapter.updateMarker`.
|
|
88
|
-
*/
|
|
89
|
-
updateMarker(options: {
|
|
90
|
-
readonly driver: SqlControlDriverInstance<string>;
|
|
91
|
-
readonly space: string;
|
|
92
|
-
readonly expectedFrom: string;
|
|
93
|
-
readonly destination: {
|
|
94
|
-
readonly storageHash: string;
|
|
95
|
-
readonly profileHash: string;
|
|
96
|
-
readonly invariants?: readonly string[];
|
|
97
|
-
};
|
|
98
|
-
}): Promise<boolean>;
|
|
99
|
-
/**
|
|
100
|
-
* Appends a ledger entry for `space`; see
|
|
101
|
-
* `SqlControlAdapter.writeLedgerEntry`.
|
|
102
|
-
*/
|
|
103
|
-
writeLedgerEntry(options: {
|
|
104
|
-
readonly driver: SqlControlDriverInstance<string>;
|
|
105
|
-
readonly space: string;
|
|
106
|
-
readonly entry: {
|
|
107
|
-
readonly edgeId: string;
|
|
108
|
-
readonly from: string;
|
|
109
|
-
readonly to: string;
|
|
110
|
-
readonly migrationName: string;
|
|
111
|
-
readonly migrationHash: string;
|
|
112
|
-
readonly operations: readonly unknown[];
|
|
113
|
-
};
|
|
114
|
-
}): Promise<void>;
|
|
115
|
-
bootstrapControlTableQueries(): readonly DdlNode[];
|
|
116
|
-
toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview;
|
|
117
|
-
}
|
|
118
|
-
//#endregion
|
|
119
|
-
//#region src/core/migrations/schema-differ.d.ts
|
|
120
|
-
/**
|
|
121
|
-
* Inputs to a SQL target's schema-differ (`diffDatabaseSchema` /
|
|
122
|
-
* `verifyDatabaseSchema` on the descriptor): the contract (the expected side
|
|
123
|
-
* derives from it), the introspected actual schema node, and the resolution
|
|
124
|
-
* context the relational diff needs.
|
|
125
|
-
*/
|
|
126
|
-
interface DiffDatabaseSchemaInput {
|
|
127
|
-
readonly contract: Contract<SqlStorage>;
|
|
128
|
-
readonly schema: SqlSchemaIRNode;
|
|
129
|
-
readonly strict: boolean;
|
|
130
|
-
readonly typeMetadataRegistry: ReadonlyMap<string, {
|
|
131
|
-
readonly nativeType?: string;
|
|
132
|
-
}>;
|
|
133
|
-
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* The `SchemaDiffer` a SQL target implements: the black-box comparison of the
|
|
137
|
-
* contract's expected schema against the introspected actual schema, projected
|
|
138
|
-
* to the two issue lists. How it computes them is private to the target.
|
|
139
|
-
*/
|
|
140
|
-
type SqlDiffDatabaseSchema = SchemaDiffer<DiffDatabaseSchemaInput>['diff'];
|
|
141
|
-
/**
|
|
142
|
-
* The same combined comparison as {@link SqlDiffDatabaseSchema}, wrapped in the
|
|
143
|
-
* verify envelope (`ok`/`summary`/`code`/`target`/`timings`) plus the
|
|
144
|
-
* pass/warn/fail tree the CLI renders. Verify calls this instead of the diff so
|
|
145
|
-
* the relational walk that produces the tree runs once per verify, not once for
|
|
146
|
-
* the diff and again for the tree.
|
|
147
|
-
*/
|
|
148
|
-
type SqlVerifyDatabaseSchema = (input: DiffDatabaseSchemaInput) => VerifyDatabaseSchemaResult;
|
|
149
|
-
//#endregion
|
|
150
11
|
//#region src/core/migrations/types.d.ts
|
|
151
12
|
type AnyRecord = Readonly<Record<string, unknown>>;
|
|
152
13
|
interface StorageTypePlanResult<TTargetDetails> {
|
|
@@ -523,48 +384,6 @@ interface SqlMigrationRunner<TTargetDetails> {
|
|
|
523
384
|
*/
|
|
524
385
|
executeOnConnection(options: SqlMigrationRunnerExecuteOptions<TTargetDetails>): Promise<SqlMigrationRunnerResult>;
|
|
525
386
|
}
|
|
526
|
-
interface SqlControlTargetDescriptor<TTargetId extends string, TTargetDetails, TContract extends Contract<SqlStorage> = Contract<SqlStorage>> extends MigratableTargetDescriptor<'sql', TTargetId, SqlControlFamilyInstance> {
|
|
527
|
-
readonly queryOperations?: () => SqlOperationDescriptors;
|
|
528
|
-
/**
|
|
529
|
-
* JSON ⇄ class boundary for the SQL target's contract. The descriptor
|
|
530
|
-
* composes a concrete `SqlContractSerializerBase` subclass; the rest
|
|
531
|
-
* of the control stack reaches `descriptor.contractSerializer` rather
|
|
532
|
-
* than importing a per-target deserialization function.
|
|
533
|
-
*/
|
|
534
|
-
readonly contractSerializer: ContractSerializer<TContract>;
|
|
535
|
-
/**
|
|
536
|
-
* Per-target schema verifier walking the contract against
|
|
537
|
-
* `SqlSchemaIR`. The descriptor composes a concrete
|
|
538
|
-
* `SqlSchemaVerifierBase` subclass; the family-shared walk lives on
|
|
539
|
-
* the base, the target-specific dispatch on the subclass.
|
|
540
|
-
*/
|
|
541
|
-
readonly schemaVerifier: SchemaVerifier<TContract, SqlSchemaIR>;
|
|
542
|
-
/**
|
|
543
|
-
* Database→PSL inference for `contract infer`. Target logic (owns the dialect
|
|
544
|
-
* maps), so it lives on the descriptor. Optional: targets without `contract
|
|
545
|
-
* infer` (Mongo) omit it, and the family instance throws when it is absent.
|
|
546
|
-
*/
|
|
547
|
-
readonly inferPslContract?: (schema: SqlSchemaIRNode) => PslDocumentAst;
|
|
548
|
-
/**
|
|
549
|
-
* The single combined database-schema diff of two derived representations —
|
|
550
|
-
* the target's black-box comparison. Every SQL target provides it (Postgres
|
|
551
|
-
* returns relational + policy issues; SQLite returns relational only). It is
|
|
552
|
-
* schema logic on the target, not database I/O, so it lives here rather than
|
|
553
|
-
* on the control adapter. How it computes the two issue sets is private.
|
|
554
|
-
* See {@link SqlDiffDatabaseSchema} / {@link SqlVerifyDatabaseSchema}.
|
|
555
|
-
*/
|
|
556
|
-
readonly diffDatabaseSchema: SqlDiffDatabaseSchema;
|
|
557
|
-
/**
|
|
558
|
-
* The same combined comparison as {@link diffDatabaseSchema}, wrapped in the
|
|
559
|
-
* verify envelope (`ok`/`summary`/`code`/`target`/`timings`) plus the
|
|
560
|
-
* pass/warn/fail tree the CLI renders. Verify calls this instead of
|
|
561
|
-
* `diffDatabaseSchema` so the relational walk that produces the tree runs
|
|
562
|
-
* once per verify, not once for the diff and again for the tree.
|
|
563
|
-
*/
|
|
564
|
-
readonly verifyDatabaseSchema: SqlVerifyDatabaseSchema;
|
|
565
|
-
createPlanner(adapter: SqlControlAdapter<TTargetId>): SqlMigrationPlanner<TTargetDetails>;
|
|
566
|
-
createRunner(family: SqlControlFamilyInstance): SqlMigrationRunner<TTargetDetails>;
|
|
567
|
-
}
|
|
568
387
|
interface CreateSqlMigrationPlanOptions<TTargetDetails> {
|
|
569
388
|
readonly targetId: string;
|
|
570
389
|
/**
|
|
@@ -583,5 +402,5 @@ interface CreateSqlMigrationPlanOptions<TTargetDetails> {
|
|
|
583
402
|
readonly meta?: AnyRecord;
|
|
584
403
|
}
|
|
585
404
|
//#endregion
|
|
586
|
-
export {
|
|
587
|
-
//# sourceMappingURL=types-
|
|
405
|
+
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 };
|
|
406
|
+
//# sourceMappingURL=types-DBxrwN1d.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-DBxrwN1d.d.mts","names":[],"sources":["../src/core/migrations/types.ts"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/family-sql",
|
|
3
|
-
"version": "0.14.0-dev.
|
|
3
|
+
"version": "0.14.0-dev.45",
|
|
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.14.0-dev.
|
|
10
|
-
"@prisma-next/emitter": "0.14.0-dev.
|
|
11
|
-
"@prisma-next/framework-components": "0.14.0-dev.
|
|
12
|
-
"@prisma-next/migration-tools": "0.14.0-dev.
|
|
13
|
-
"@prisma-next/operations": "0.14.0-dev.
|
|
14
|
-
"@prisma-next/sql-contract": "0.14.0-dev.
|
|
15
|
-
"@prisma-next/sql-contract-emitter": "0.14.0-dev.
|
|
16
|
-
"@prisma-next/sql-contract-ts": "0.14.0-dev.
|
|
17
|
-
"@prisma-next/sql-operations": "0.14.0-dev.
|
|
18
|
-
"@prisma-next/sql-relational-core": "0.14.0-dev.
|
|
19
|
-
"@prisma-next/sql-runtime": "0.14.0-dev.
|
|
20
|
-
"@prisma-next/sql-schema-ir": "0.14.0-dev.
|
|
21
|
-
"@prisma-next/utils": "0.14.0-dev.
|
|
9
|
+
"@prisma-next/contract": "0.14.0-dev.45",
|
|
10
|
+
"@prisma-next/emitter": "0.14.0-dev.45",
|
|
11
|
+
"@prisma-next/framework-components": "0.14.0-dev.45",
|
|
12
|
+
"@prisma-next/migration-tools": "0.14.0-dev.45",
|
|
13
|
+
"@prisma-next/operations": "0.14.0-dev.45",
|
|
14
|
+
"@prisma-next/sql-contract": "0.14.0-dev.45",
|
|
15
|
+
"@prisma-next/sql-contract-emitter": "0.14.0-dev.45",
|
|
16
|
+
"@prisma-next/sql-contract-ts": "0.14.0-dev.45",
|
|
17
|
+
"@prisma-next/sql-operations": "0.14.0-dev.45",
|
|
18
|
+
"@prisma-next/sql-relational-core": "0.14.0-dev.45",
|
|
19
|
+
"@prisma-next/sql-runtime": "0.14.0-dev.45",
|
|
20
|
+
"@prisma-next/sql-schema-ir": "0.14.0-dev.45",
|
|
21
|
+
"@prisma-next/utils": "0.14.0-dev.45",
|
|
22
22
|
"arktype": "^2.2.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@prisma-next/driver-postgres": "0.14.0-dev.
|
|
26
|
-
"@prisma-next/psl-parser": "0.14.0-dev.
|
|
27
|
-
"@prisma-next/psl-printer": "0.14.0-dev.
|
|
28
|
-
"@prisma-next/sql-contract-psl": "0.14.0-dev.
|
|
29
|
-
"@prisma-next/test-utils": "0.14.0-dev.
|
|
30
|
-
"@prisma-next/tsconfig": "0.14.0-dev.
|
|
31
|
-
"@prisma-next/tsdown": "0.14.0-dev.
|
|
25
|
+
"@prisma-next/driver-postgres": "0.14.0-dev.45",
|
|
26
|
+
"@prisma-next/psl-parser": "0.14.0-dev.45",
|
|
27
|
+
"@prisma-next/psl-printer": "0.14.0-dev.45",
|
|
28
|
+
"@prisma-next/sql-contract-psl": "0.14.0-dev.45",
|
|
29
|
+
"@prisma-next/test-utils": "0.14.0-dev.45",
|
|
30
|
+
"@prisma-next/tsconfig": "0.14.0-dev.45",
|
|
31
|
+
"@prisma-next/tsdown": "0.14.0-dev.45",
|
|
32
32
|
"tsdown": "0.22.1",
|
|
33
33
|
"typescript": "5.9.3",
|
|
34
34
|
"vitest": "4.1.8"
|
|
@@ -48,6 +48,10 @@ import type { SqlSchemaIRNode, SqlTableIR } from '@prisma-next/sql-schema-ir/typ
|
|
|
48
48
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
49
49
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
50
50
|
import type { SqlControlAdapter } from './control-adapter';
|
|
51
|
+
import type {
|
|
52
|
+
SqlControlTargetDescriptor,
|
|
53
|
+
SqlDescribedContractSpace,
|
|
54
|
+
} from './control-target-descriptor';
|
|
51
55
|
import { SqlContractSerializer } from './ir/sql-contract-serializer';
|
|
52
56
|
import type { DiffDatabaseSchemaInput } from './migrations/schema-differ';
|
|
53
57
|
import type {
|
|
@@ -535,9 +539,21 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
535
539
|
// maps and walks its own schema tree), so it is read off the descriptor like
|
|
536
540
|
// `contractSerializer`. Absent for targets without `contract infer` (Mongo).
|
|
537
541
|
const targetInferPslContract = blindCast<
|
|
538
|
-
|
|
542
|
+
SqlControlTargetDescriptor<TTargetId, unknown>,
|
|
539
543
|
'reading the optional target-descriptor inferPslContract hook'
|
|
540
544
|
>(target).inferPslContract;
|
|
545
|
+
// `contract infer` needs each extension pack's already-assembled contract,
|
|
546
|
+
// carried as-is (no merging — that is the contract-spaces machinery's
|
|
547
|
+
// concern), paired with the `spaceId` its descriptor was registered under
|
|
548
|
+
// (neither the contract JSON nor `ContractSpace` self-declares it), so the
|
|
549
|
+
// target hook can omit elements those contracts describe and qualify a
|
|
550
|
+
// cross-space relation with the owning pack's space id.
|
|
551
|
+
const describedContracts: readonly SqlDescribedContractSpace[] = extensions.flatMap(
|
|
552
|
+
(extension) =>
|
|
553
|
+
extension.contractSpace
|
|
554
|
+
? [{ spaceId: extension.id, contract: extension.contractSpace.contractJson }]
|
|
555
|
+
: [],
|
|
556
|
+
);
|
|
541
557
|
// The combined database-schema verify is a required target-descriptor
|
|
542
558
|
// operation: every SQL target provides it, wrapping the same comparison
|
|
543
559
|
// `diffDatabaseSchema` runs in the verify envelope plus the pass/warn/fail
|
|
@@ -923,7 +939,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
923
939
|
`Target "${target.targetId}" does not support contract infer (no inferPslContract on its descriptor).`,
|
|
924
940
|
);
|
|
925
941
|
}
|
|
926
|
-
return targetInferPslContract(schemaIR);
|
|
942
|
+
return targetInferPslContract(schemaIR, describedContracts);
|
|
927
943
|
},
|
|
928
944
|
|
|
929
945
|
lowerAst(
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Contract } from '@prisma-next/contract/types';
|
|
2
|
+
import type {
|
|
3
|
+
ContractSerializer,
|
|
4
|
+
MigratableTargetDescriptor,
|
|
5
|
+
SchemaVerifier,
|
|
6
|
+
} from '@prisma-next/framework-components/control';
|
|
7
|
+
import type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';
|
|
8
|
+
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
9
|
+
import type { SqlOperationDescriptors } from '@prisma-next/sql-operations';
|
|
10
|
+
import type { SqlSchemaIR, SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
11
|
+
import type { SqlControlAdapter } from './control-adapter';
|
|
12
|
+
import type { SqlControlFamilyInstance } from './control-instance';
|
|
13
|
+
import type { SqlDiffDatabaseSchema, SqlVerifyDatabaseSchema } from './migrations/schema-differ';
|
|
14
|
+
import type { SqlMigrationPlanner, SqlMigrationRunner } from './migrations/types';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* One stack extension pack's already-assembled contract, paired with the
|
|
18
|
+
* `spaceId` its extension descriptor was registered under. `contract infer`
|
|
19
|
+
* needs both: the contract to know which elements the pack describes and to
|
|
20
|
+
* resolve the domain model a cross-space foreign key targets, the `spaceId`
|
|
21
|
+
* to qualify the emitted relation type (`<spaceId>:<namespace>.<Model>`).
|
|
22
|
+
* Neither the contract JSON nor the framework's `ContractSpace` wrapper
|
|
23
|
+
* self-declares its owning space id — it is only known from the extension
|
|
24
|
+
* descriptor that carries the `ContractSpace`.
|
|
25
|
+
*/
|
|
26
|
+
export interface SqlDescribedContractSpace {
|
|
27
|
+
readonly spaceId: string;
|
|
28
|
+
readonly contract: Contract<SqlStorage>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface SqlControlTargetDescriptor<
|
|
32
|
+
TTargetId extends string,
|
|
33
|
+
TTargetDetails,
|
|
34
|
+
TContract extends Contract<SqlStorage> = Contract<SqlStorage>,
|
|
35
|
+
> extends MigratableTargetDescriptor<'sql', TTargetId, SqlControlFamilyInstance> {
|
|
36
|
+
readonly queryOperations?: () => SqlOperationDescriptors;
|
|
37
|
+
/**
|
|
38
|
+
* JSON ⇄ class boundary for the SQL target's contract. The descriptor
|
|
39
|
+
* composes a concrete `SqlContractSerializerBase` subclass; the rest
|
|
40
|
+
* of the control stack reaches `descriptor.contractSerializer` rather
|
|
41
|
+
* than importing a per-target deserialization function.
|
|
42
|
+
*/
|
|
43
|
+
readonly contractSerializer: ContractSerializer<TContract>;
|
|
44
|
+
/**
|
|
45
|
+
* Per-target schema verifier walking the contract against
|
|
46
|
+
* `SqlSchemaIR`. The descriptor composes a concrete
|
|
47
|
+
* `SqlSchemaVerifierBase` subclass; the family-shared walk lives on
|
|
48
|
+
* the base, the target-specific dispatch on the subclass.
|
|
49
|
+
*/
|
|
50
|
+
readonly schemaVerifier: SchemaVerifier<TContract, SqlSchemaIR>;
|
|
51
|
+
/**
|
|
52
|
+
* Database→PSL inference for `contract infer`. Target logic (owns the dialect
|
|
53
|
+
* maps), so it lives on the descriptor. Optional: targets without `contract
|
|
54
|
+
* infer` (Mongo) omit it, and the family instance throws when it is absent.
|
|
55
|
+
* `describedContracts` carries the stack's extension packs' already-assembled
|
|
56
|
+
* contracts (each paired with its `spaceId`) so the inferrer can omit elements
|
|
57
|
+
* they already describe, and can qualify a cross-space relation with the
|
|
58
|
+
* owning pack's space id.
|
|
59
|
+
*/
|
|
60
|
+
readonly inferPslContract?: (
|
|
61
|
+
schema: SqlSchemaIRNode,
|
|
62
|
+
describedContracts?: readonly SqlDescribedContractSpace[],
|
|
63
|
+
) => PslDocumentAst;
|
|
64
|
+
/**
|
|
65
|
+
* The single combined database-schema diff of two derived representations —
|
|
66
|
+
* the target's black-box comparison. Every SQL target provides it (Postgres
|
|
67
|
+
* returns relational + policy issues; SQLite returns relational only). It is
|
|
68
|
+
* schema logic on the target, not database I/O, so it lives here rather than
|
|
69
|
+
* on the control adapter. How it computes the two issue sets is private.
|
|
70
|
+
* See {@link SqlDiffDatabaseSchema} / {@link SqlVerifyDatabaseSchema}.
|
|
71
|
+
*/
|
|
72
|
+
readonly diffDatabaseSchema: SqlDiffDatabaseSchema;
|
|
73
|
+
/**
|
|
74
|
+
* The same combined comparison as {@link diffDatabaseSchema}, wrapped in the
|
|
75
|
+
* verify envelope (`ok`/`summary`/`code`/`target`/`timings`) plus the
|
|
76
|
+
* pass/warn/fail tree the CLI renders. Verify calls this instead of
|
|
77
|
+
* `diffDatabaseSchema` so the relational walk that produces the tree runs
|
|
78
|
+
* once per verify, not once for the diff and again for the tree.
|
|
79
|
+
*/
|
|
80
|
+
readonly verifyDatabaseSchema: SqlVerifyDatabaseSchema;
|
|
81
|
+
createPlanner(adapter: SqlControlAdapter<TTargetId>): SqlMigrationPlanner<TTargetDetails>;
|
|
82
|
+
createRunner(family: SqlControlFamilyInstance): SqlMigrationRunner<TTargetDetails>;
|
|
83
|
+
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
2
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
3
3
|
import type {
|
|
4
|
-
ContractSerializer,
|
|
5
4
|
ContractSpace,
|
|
6
5
|
ControlAdapterDescriptor,
|
|
7
6
|
ControlExtensionDescriptor,
|
|
8
7
|
DiffIssue,
|
|
9
|
-
MigratableTargetDescriptor,
|
|
10
8
|
MigrationOperationPolicy,
|
|
11
9
|
MigrationPlan,
|
|
12
10
|
MigrationPlannerConflict,
|
|
@@ -20,9 +18,7 @@ import type {
|
|
|
20
18
|
OperationContext,
|
|
21
19
|
OpFactoryCall,
|
|
22
20
|
SchemaIssue,
|
|
23
|
-
SchemaVerifier,
|
|
24
21
|
} from '@prisma-next/framework-components/control';
|
|
25
|
-
import type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';
|
|
26
22
|
import type { AggregateMigrationEdgeRef } from '@prisma-next/migration-tools/aggregate';
|
|
27
23
|
import type {
|
|
28
24
|
SqlControlDriverInstance,
|
|
@@ -35,8 +31,6 @@ import type { SqlOperationDescriptors } from '@prisma-next/sql-operations';
|
|
|
35
31
|
import type { SqlSchemaIR, SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
36
32
|
import type { Result } from '@prisma-next/utils/result';
|
|
37
33
|
import type { SqlControlAdapter } from '../control-adapter';
|
|
38
|
-
import type { SqlControlFamilyInstance } from '../control-instance';
|
|
39
|
-
import type { SqlDiffDatabaseSchema, SqlVerifyDatabaseSchema } from './schema-differ';
|
|
40
34
|
|
|
41
35
|
export type AnyRecord = Readonly<Record<string, unknown>>;
|
|
42
36
|
|
|
@@ -474,53 +468,6 @@ export interface SqlMigrationRunner<TTargetDetails> {
|
|
|
474
468
|
): Promise<SqlMigrationRunnerResult>;
|
|
475
469
|
}
|
|
476
470
|
|
|
477
|
-
export interface SqlControlTargetDescriptor<
|
|
478
|
-
TTargetId extends string,
|
|
479
|
-
TTargetDetails,
|
|
480
|
-
TContract extends Contract<SqlStorage> = Contract<SqlStorage>,
|
|
481
|
-
> extends MigratableTargetDescriptor<'sql', TTargetId, SqlControlFamilyInstance> {
|
|
482
|
-
readonly queryOperations?: () => SqlOperationDescriptors;
|
|
483
|
-
/**
|
|
484
|
-
* JSON ⇄ class boundary for the SQL target's contract. The descriptor
|
|
485
|
-
* composes a concrete `SqlContractSerializerBase` subclass; the rest
|
|
486
|
-
* of the control stack reaches `descriptor.contractSerializer` rather
|
|
487
|
-
* than importing a per-target deserialization function.
|
|
488
|
-
*/
|
|
489
|
-
readonly contractSerializer: ContractSerializer<TContract>;
|
|
490
|
-
/**
|
|
491
|
-
* Per-target schema verifier walking the contract against
|
|
492
|
-
* `SqlSchemaIR`. The descriptor composes a concrete
|
|
493
|
-
* `SqlSchemaVerifierBase` subclass; the family-shared walk lives on
|
|
494
|
-
* the base, the target-specific dispatch on the subclass.
|
|
495
|
-
*/
|
|
496
|
-
readonly schemaVerifier: SchemaVerifier<TContract, SqlSchemaIR>;
|
|
497
|
-
/**
|
|
498
|
-
* Database→PSL inference for `contract infer`. Target logic (owns the dialect
|
|
499
|
-
* maps), so it lives on the descriptor. Optional: targets without `contract
|
|
500
|
-
* infer` (Mongo) omit it, and the family instance throws when it is absent.
|
|
501
|
-
*/
|
|
502
|
-
readonly inferPslContract?: (schema: SqlSchemaIRNode) => PslDocumentAst;
|
|
503
|
-
/**
|
|
504
|
-
* The single combined database-schema diff of two derived representations —
|
|
505
|
-
* the target's black-box comparison. Every SQL target provides it (Postgres
|
|
506
|
-
* returns relational + policy issues; SQLite returns relational only). It is
|
|
507
|
-
* schema logic on the target, not database I/O, so it lives here rather than
|
|
508
|
-
* on the control adapter. How it computes the two issue sets is private.
|
|
509
|
-
* See {@link SqlDiffDatabaseSchema} / {@link SqlVerifyDatabaseSchema}.
|
|
510
|
-
*/
|
|
511
|
-
readonly diffDatabaseSchema: SqlDiffDatabaseSchema;
|
|
512
|
-
/**
|
|
513
|
-
* The same combined comparison as {@link diffDatabaseSchema}, wrapped in the
|
|
514
|
-
* verify envelope (`ok`/`summary`/`code`/`target`/`timings`) plus the
|
|
515
|
-
* pass/warn/fail tree the CLI renders. Verify calls this instead of
|
|
516
|
-
* `diffDatabaseSchema` so the relational walk that produces the tree runs
|
|
517
|
-
* once per verify, not once for the diff and again for the tree.
|
|
518
|
-
*/
|
|
519
|
-
readonly verifyDatabaseSchema: SqlVerifyDatabaseSchema;
|
|
520
|
-
createPlanner(adapter: SqlControlAdapter<TTargetId>): SqlMigrationPlanner<TTargetDetails>;
|
|
521
|
-
createRunner(family: SqlControlFamilyInstance): SqlMigrationRunner<TTargetDetails>;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
471
|
export interface CreateSqlMigrationPlanOptions<TTargetDetails> {
|
|
525
472
|
readonly targetId: string;
|
|
526
473
|
/**
|
|
@@ -37,6 +37,18 @@ export interface PslPrinterOptions {
|
|
|
37
37
|
export type RelationField = {
|
|
38
38
|
readonly fieldName: string;
|
|
39
39
|
readonly typeName: string;
|
|
40
|
+
/**
|
|
41
|
+
* Namespace qualifier for a cross-space relation (e.g. `"auth"` for a
|
|
42
|
+
* relation into `supabase:auth.AuthUser`). Absent for a same-namespace
|
|
43
|
+
* relation.
|
|
44
|
+
*/
|
|
45
|
+
readonly typeNamespaceId?: string | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Contract-space qualifier for a relation into another stack extension
|
|
48
|
+
* pack's contract space (e.g. `"supabase"`). Absent for a same-space
|
|
49
|
+
* relation.
|
|
50
|
+
*/
|
|
51
|
+
readonly typeContractSpaceId?: string | undefined;
|
|
40
52
|
readonly referencedTableName?: string | undefined;
|
|
41
53
|
readonly optional: boolean;
|
|
42
54
|
readonly list: boolean;
|