@prisma-next/family-sql 0.14.0-dev.61 → 0.14.0-dev.63
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 +42 -30
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +31 -62
- package/dist/control.mjs.map +1 -1
- package/dist/diff.d.mts +4 -4
- package/dist/migration.d.mts +1 -1
- package/dist/schema-verify-W3r631Jh.mjs.map +1 -1
- package/dist/{types-COTsneBU.d.mts → types-9DnjnhkE.d.mts} +6 -7
- package/dist/types-9DnjnhkE.d.mts.map +1 -0
- package/package.json +21 -21
- package/src/core/diff/schema-verify.ts +3 -3
- package/src/core/migrations/control-policy.ts +66 -115
- package/src/core/migrations/types.ts +5 -6
- package/src/exports/control.ts +1 -1
- package/dist/types-COTsneBU.d.mts.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-BeN8TDZ5.mjs";
|
|
2
|
-
import { n as CodecControlHooks } from "./types-
|
|
2
|
+
import { n as CodecControlHooks } from "./types-9DnjnhkE.mjs";
|
|
3
3
|
import { t as SqlSchemaDiffFn } from "./schema-differ-DnoopSXm.mjs";
|
|
4
4
|
import { DiffSubjectGranularity, SchemaDiffIssue, VerifierIssueCategory, VerifyDatabaseSchemaResult } from "@prisma-next/framework-components/control";
|
|
5
5
|
import { Contract, ControlPolicy } from "@prisma-next/contract/types";
|
|
@@ -70,9 +70,9 @@ interface StorageTypeVerdictInput {
|
|
|
70
70
|
/**
|
|
71
71
|
* Runs the codec `verifyType` hooks the way the legacy walk did: once per
|
|
72
72
|
* contract namespace with tables, against that namespace's paired actual
|
|
73
|
-
* node (the hook reads namespace-scoped state such as
|
|
74
|
-
*
|
|
75
|
-
*
|
|
73
|
+
* node (the hook reads namespace-scoped state such as `enums` off it).
|
|
74
|
+
* Issue dispositions grade against the contract default policy, matching
|
|
75
|
+
* the legacy `pushTypeNode` semantics.
|
|
76
76
|
*/
|
|
77
77
|
interface StorageTypeVerdict {
|
|
78
78
|
readonly failures: readonly SchemaDiffIssue[];
|
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-9DnjnhkE.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";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-verify-W3r631Jh.mjs","names":["d"],"sources":["../src/core/assembly.ts","../src/core/diff/verifier-disposition.ts","../src/core/diff/schema-verify.ts"],"sourcesContent":["import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport { assertUniqueCodecOwner } from '@prisma-next/framework-components/control';\nimport type { CodecControlHooks } from './migrations/types';\n\ntype CodecControlHooksMap = Record<string, CodecControlHooks>;\n\nfunction hasCodecControlHooks(descriptor: unknown): descriptor is {\n readonly id: string;\n readonly types: {\n readonly codecTypes: {\n readonly controlPlaneHooks: CodecControlHooksMap;\n };\n };\n} {\n if (typeof descriptor !== 'object' || descriptor === null) {\n return false;\n }\n const d = descriptor as { types?: { codecTypes?: { controlPlaneHooks?: unknown } } };\n const hooks = d.types?.codecTypes?.controlPlaneHooks;\n return hooks !== null && hooks !== undefined && typeof hooks === 'object';\n}\n\nexport function extractCodecControlHooks(\n descriptors: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>,\n): Map<string, CodecControlHooks> {\n const hooks = new Map<string, CodecControlHooks>();\n const owners = new Map<string, string>();\n\n for (const descriptor of descriptors) {\n if (typeof descriptor !== 'object' || descriptor === null) {\n continue;\n }\n if (!hasCodecControlHooks(descriptor)) {\n continue;\n }\n const controlPlaneHooks = descriptor.types.codecTypes.controlPlaneHooks;\n for (const [codecId, hook] of Object.entries(controlPlaneHooks)) {\n assertUniqueCodecOwner({\n codecId,\n owners,\n descriptorId: descriptor.id,\n entityLabel: 'control hooks',\n entityOwnershipLabel: 'owner',\n });\n hooks.set(codecId, hook);\n owners.set(codecId, descriptor.id);\n }\n }\n\n return hooks;\n}\n","import type { ControlPolicy } from '@prisma-next/contract/types';\nimport type {\n SchemaDiffIssue,\n VerifierIssueCategory,\n VerifierOutcome,\n} from '@prisma-next/framework-components/control';\nimport { dispositionForCategory } from '@prisma-next/framework-components/control';\n\n/**\n * Classifies a codec `verifyType` hook finding into the target-neutral\n * categories the framework grades. A storage type is a named type instance\n * (e.g. a native enum); the only shape divergence it can carry is a change\n * to its value set, so a paired mismatch always classifies as `valueDrift`.\n */\nexport function classifyStorageTypeDiffIssue(issue: SchemaDiffIssue): VerifierIssueCategory {\n if (issue.reason === 'not-found') {\n return 'declaredMissing';\n }\n if (issue.reason === 'not-expected') {\n return 'extraAuxiliary';\n }\n return 'valueDrift';\n}\n\nexport function verifierDisposition(\n controlPolicy: ControlPolicy,\n issue: SchemaDiffIssue,\n): VerifierOutcome {\n return dispositionForCategory(controlPolicy, classifyStorageTypeDiffIssue(issue));\n}\n","/**\n * The differ-based SQL schema verify: post-diff filters and verdict.\n *\n * The generic node differ (`diffSchemas`) reports every node-level\n * difference between the derived expected tree and the introspected actual\n * tree. This module is the consumer side the spec assigns to the SQL\n * family: strict-mode extras gating and control-policy disposition are\n * reason/kind-keyed filters applied AFTER the diff — never inside it — and\n * the verify verdict derives from the filtered issue list.\n *\n * `verifySqlSchemaByDiff` wraps the verdict in the issue-based result\n * envelope — this is THE SQL schema verify (the legacy relational walk and\n * its verification tree are retired).\n */\n\nimport type { Contract, ControlPolicy } from '@prisma-next/contract/types';\nimport { effectiveControlPolicy } from '@prisma-next/contract/types';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n DiffSubjectGranularity,\n SchemaDiffIssue,\n VerifierIssueCategory,\n VerifierOutcome,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport { dispositionForCategory } from '@prisma-next/framework-components/control';\nimport { isStorageTypeInstance, type SqlStorage } from '@prisma-next/sql-contract/types';\nimport { RelationalSchemaNodeKind, type SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { extractCodecControlHooks } from '../assembly';\nimport type { SqlSchemaDiffFn } from '../migrations/schema-differ';\nimport type { CodecControlHooks } from '../migrations/types';\nimport { verifierDisposition } from './verifier-disposition';\n\n// ============================================================================\n// Subject-granularity classification — nodeKind → framework-neutral granularity\n// ============================================================================\n\nfunction issueNode(issue: SchemaDiffIssue): SqlSchemaIRNode | undefined {\n const node = issue.expected ?? issue.actual;\n if (node === undefined) return undefined;\n return blindCast<\n SqlSchemaIRNode,\n 'every node in a SQL schema diff tree is a SqlSchemaIRNode; nodeKind is its identity'\n >(node);\n}\n\n/**\n * Resolves an issue's framework-neutral {@link DiffSubjectGranularity} on\n * demand, from the issue's node's `nodeKind` via the target-provided\n * `granularityOf` map. The node carries only its `nodeKind` identity, never a\n * classification, and nothing is stamped onto the issue — every consumer\n * (the family verdict below, the framework aggregate's unclaimed-elements\n * sweep via {@link import('@prisma-next/framework-components/control').SchemaSubjectClassifierCapable})\n * calls this the same way, resolved by the family/target that owns the node\n * vocabulary. `undefined` for an issue with no node.\n */\nexport function classifyDiffSubjectGranularity(\n issue: SchemaDiffIssue,\n granularityOf: (nodeKind: string) => DiffSubjectGranularity,\n): DiffSubjectGranularity | undefined {\n const node = issueNode(issue);\n return node === undefined ? undefined : granularityOf(node.nodeKind);\n}\n\n/**\n * Resolves an issue's storage `entityKind` on demand, from the issue's\n * node's `nodeKind` via the target-provided `entityKindOf` map — the sibling\n * of {@link classifyDiffSubjectGranularity}, called the same way by the same\n * consumers (via\n * {@link import('@prisma-next/framework-components/control').SchemaSubjectClassifierCapable}).\n * `undefined` for an issue with no node, or for a node kind with no storage\n * entity of its own.\n */\nexport function classifyDiffEntityKind(\n issue: SchemaDiffIssue,\n entityKindOf: (nodeKind: string) => string | undefined,\n): string | undefined {\n const node = issueNode(issue);\n return node === undefined ? undefined : entityKindOf(node.nodeKind);\n}\n\n// ============================================================================\n// Issue classification — subject granularity + reason → target-neutral category\n// ============================================================================\n\n/**\n * Re-keys the legacy `classifySqlVerifierIssueKind` category mapping on the\n * issue's {@link DiffSubjectGranularity} (resolved via `granularityOf`) + the\n * issue reason. The vocabulary maps one-to-one: an undeclared live entity or\n * namespace is `extraTopLevelObject`, an undeclared live field\n * `extraNestedElement`, undeclared auxiliaries (constraints, indexes,\n * defaults) and structural leaves (policies) `extraAuxiliary`; a value-set\n * drift on a check node is `valueDrift`; every other paired divergence is\n * `declaredIncompatible`; anything the database lacks is `declaredMissing`.\n * `granularityOf` is the target's classifier, so target and extension node\n * kinds classify without the family importing them.\n */\nexport function classifySqlDiffIssue(\n issue: SchemaDiffIssue,\n granularityOf: (nodeKind: string) => DiffSubjectGranularity,\n): VerifierIssueCategory {\n if (issue.reason === 'not-found') {\n return 'declaredMissing';\n }\n if (issue.reason === 'not-expected') {\n const granularity = classifyDiffSubjectGranularity(issue, granularityOf);\n if (granularity === 'entity' || granularity === 'namespace') {\n return 'extraTopLevelObject';\n }\n if (granularity === 'field') {\n return 'extraNestedElement';\n }\n return 'extraAuxiliary';\n }\n if (issueNode(issue)?.nodeKind === RelationalSchemaNodeKind.check) {\n return 'valueDrift';\n }\n return 'declaredIncompatible';\n}\n\n/**\n * Whether a `not-expected` issue is a strict-mode-only finding. The legacy\n * walk detected every relational extra (namespaces, entities, fields, and\n * their auxiliaries) only under `--strict`; the structural diff (roots, RLS\n * policies, roles) was never strict-gated — its extras fail in both modes.\n * Keyed on the issue's granularity, resolved via `granularityOf`.\n */\nfunction isStrictOnlyExtra(\n issue: SchemaDiffIssue,\n granularityOf: (nodeKind: string) => DiffSubjectGranularity,\n): boolean {\n const granularity = classifyDiffSubjectGranularity(issue, granularityOf);\n return (\n granularity === 'namespace' ||\n granularity === 'entity' ||\n granularity === 'field' ||\n granularity === 'auxiliary'\n );\n}\n\n// ============================================================================\n// The post-diff filter + verdict\n// ============================================================================\n\nexport interface SqlDiffVerdictInput {\n /** The full, ownership-scoped diff issue list from the target's differ. */\n readonly issues: readonly SchemaDiffIssue[];\n /** Resolves a diff issue's subject table's declared control policy directly from the contract. */\n readonly resolveControlPolicy: (issue: SchemaDiffIssue) => ControlPolicy | undefined;\n readonly strict: boolean;\n readonly defaultControlPolicy: ControlPolicy | undefined;\n /** The target's classifier: a diff issue node's `nodeKind` → its subject granularity. */\n readonly granularityOf: (nodeKind: string) => DiffSubjectGranularity;\n}\n\nexport interface SqlDiffVerdict {\n readonly failures: readonly SchemaDiffIssue[];\n readonly warnings: readonly SchemaDiffIssue[];\n}\n\n/**\n * Applies the two consumer filters to a diff issue list: strict gating\n * (relational `not-expected` findings drop in lenient mode) and\n * control-policy disposition (each surviving issue grades against its\n * subject table's effective policy; suppressed issues drop, `observed`\n * subjects warn). The verify verdict is `failures.length === 0`.\n */\nexport function computeSqlDiffVerdict(input: SqlDiffVerdictInput): SqlDiffVerdict {\n const failures: SchemaDiffIssue[] = [];\n const warnings: SchemaDiffIssue[] = [];\n for (const issue of input.issues) {\n if (\n !input.strict &&\n issue.reason === 'not-expected' &&\n isStrictOnlyExtra(issue, input.granularityOf)\n ) {\n continue;\n }\n const tablePolicy = input.resolveControlPolicy(issue);\n const policy = effectiveControlPolicy(tablePolicy, input.defaultControlPolicy);\n const disposition: VerifierOutcome = dispositionForCategory(\n policy,\n classifySqlDiffIssue(issue, input.granularityOf),\n );\n if (disposition === 'suppress') continue;\n if (disposition === 'warn') {\n warnings.push(issue);\n continue;\n }\n failures.push(issue);\n }\n return { failures, warnings };\n}\n\n// ============================================================================\n// Storage-types check — the codec verifyType hook path\n// ============================================================================\n\nexport interface StorageTypeVerdictInput {\n readonly contract: Contract<SqlStorage>;\n /**\n * Expected/actual namespace-node pairs the target's differ input produced:\n * for a namespaced tree, one entry per expected namespace with a\n * non-empty table set, paired by DDL schema name (absent actual side for\n * a schema the database lacks); a flat tree is the sole pair.\n */\n readonly namespacePairs: ReadonlyArray<{\n readonly actual: SqlSchemaIRNode | undefined;\n }>;\n readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;\n}\n\n/**\n * Runs the codec `verifyType` hooks the way the legacy walk did: once per\n * contract namespace with tables, against that namespace's paired actual\n * node (the hook reads namespace-scoped state such as\n * `nativeEnumTypeNames` off it). Issue dispositions grade against the\n * contract default policy, matching the legacy `pushTypeNode` semantics.\n */\nexport interface StorageTypeVerdict {\n readonly failures: readonly SchemaDiffIssue[];\n readonly warnings: readonly SchemaDiffIssue[];\n}\n\nexport function computeStorageTypeVerdict(input: StorageTypeVerdictInput): StorageTypeVerdict {\n const failures: SchemaDiffIssue[] = [];\n const warnings: SchemaDiffIssue[] = [];\n const policy = effectiveControlPolicy(undefined, input.contract.defaultControlPolicy);\n for (const pair of input.namespacePairs) {\n if (pair.actual === undefined) continue;\n for (const [typeName, typeInstance] of Object.entries(input.contract.storage.types ?? {})) {\n if (!isStorageTypeInstance(typeInstance)) continue;\n const hook = input.codecHooks.get(typeInstance.codecId);\n if (!hook?.verifyType) continue;\n const typeIssues = hook.verifyType({ typeName, typeInstance, schema: pair.actual });\n for (const issue of typeIssues) {\n const disposition = verifierDisposition(policy, issue);\n if (disposition === 'suppress') continue;\n if (disposition === 'warn') {\n warnings.push(issue);\n continue;\n }\n failures.push(issue);\n }\n }\n }\n return { failures, warnings };\n}\n\n// ============================================================================\n// The issue-based verify envelope\n// ============================================================================\n\nexport interface VerifySqlSchemaByDiffInput {\n readonly contract: Contract<SqlStorage>;\n readonly schema: SqlSchemaIRNode;\n readonly strict: boolean;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n /** The target's full-tree node diff (`diffSchema` descriptor hook). */\n readonly diffSchema: SqlSchemaDiffFn;\n /** The target's classifier: a diff issue node's `nodeKind` → its subject granularity. */\n readonly granularityOf: (nodeKind: string) => DiffSubjectGranularity;\n}\n\n/**\n * THE SQL schema verify: runs the target's full-tree node diff, grades it\n * through the family's post-diff filters (strict gating + control-policy\n * disposition) plus the codec `verifyType` hook findings, and wraps the\n * verdict in the issue-based result envelope. `ok` holds exactly when both\n * issue lists are empty — the lists carry the verdict's failures.\n */\nexport function verifySqlSchemaByDiff(\n input: VerifySqlSchemaByDiffInput,\n): VerifyDatabaseSchemaResult {\n const startTime = Date.now();\n const verdictDiff = input.diffSchema({\n contract: input.contract,\n schema: input.schema,\n frameworkComponents: input.frameworkComponents,\n });\n const diffVerdict = computeSqlDiffVerdict({\n issues: verdictDiff.issues,\n resolveControlPolicy: verdictDiff.resolveControlPolicy,\n strict: input.strict,\n defaultControlPolicy: input.contract.defaultControlPolicy,\n granularityOf: input.granularityOf,\n });\n const storageTypeVerdict = computeStorageTypeVerdict({\n contract: input.contract,\n namespacePairs: verdictDiff.namespacePairs,\n codecHooks: extractCodecControlHooks(input.frameworkComponents),\n });\n const failCount = diffVerdict.failures.length + storageTypeVerdict.failures.length;\n const ok = failCount === 0;\n const profileHash =\n 'profileHash' in input.contract && typeof input.contract.profileHash === 'string'\n ? input.contract.profileHash\n : undefined;\n return {\n ok,\n ...(ok ? {} : { code: 'PN-SCHEMA-0001' }),\n summary: ok\n ? 'Database schema satisfies contract'\n : `Database schema does not satisfy contract (${failCount} failure${failCount === 1 ? '' : 's'})`,\n contract: {\n storageHash: input.contract.storage.storageHash,\n ...ifDefined('profileHash', profileHash),\n },\n target: {\n expected: input.contract.target,\n actual: input.contract.target,\n },\n schema: {\n issues: [...diffVerdict.failures, ...storageTypeVerdict.failures],\n warnings: {\n issues: [...diffVerdict.warnings, ...storageTypeVerdict.warnings],\n },\n },\n meta: { strict: input.strict },\n timings: { total: Date.now() - startTime },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema-verify-W3r631Jh.mjs","names":["d"],"sources":["../src/core/assembly.ts","../src/core/diff/verifier-disposition.ts","../src/core/diff/schema-verify.ts"],"sourcesContent":["import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport { assertUniqueCodecOwner } from '@prisma-next/framework-components/control';\nimport type { CodecControlHooks } from './migrations/types';\n\ntype CodecControlHooksMap = Record<string, CodecControlHooks>;\n\nfunction hasCodecControlHooks(descriptor: unknown): descriptor is {\n readonly id: string;\n readonly types: {\n readonly codecTypes: {\n readonly controlPlaneHooks: CodecControlHooksMap;\n };\n };\n} {\n if (typeof descriptor !== 'object' || descriptor === null) {\n return false;\n }\n const d = descriptor as { types?: { codecTypes?: { controlPlaneHooks?: unknown } } };\n const hooks = d.types?.codecTypes?.controlPlaneHooks;\n return hooks !== null && hooks !== undefined && typeof hooks === 'object';\n}\n\nexport function extractCodecControlHooks(\n descriptors: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>,\n): Map<string, CodecControlHooks> {\n const hooks = new Map<string, CodecControlHooks>();\n const owners = new Map<string, string>();\n\n for (const descriptor of descriptors) {\n if (typeof descriptor !== 'object' || descriptor === null) {\n continue;\n }\n if (!hasCodecControlHooks(descriptor)) {\n continue;\n }\n const controlPlaneHooks = descriptor.types.codecTypes.controlPlaneHooks;\n for (const [codecId, hook] of Object.entries(controlPlaneHooks)) {\n assertUniqueCodecOwner({\n codecId,\n owners,\n descriptorId: descriptor.id,\n entityLabel: 'control hooks',\n entityOwnershipLabel: 'owner',\n });\n hooks.set(codecId, hook);\n owners.set(codecId, descriptor.id);\n }\n }\n\n return hooks;\n}\n","import type { ControlPolicy } from '@prisma-next/contract/types';\nimport type {\n SchemaDiffIssue,\n VerifierIssueCategory,\n VerifierOutcome,\n} from '@prisma-next/framework-components/control';\nimport { dispositionForCategory } from '@prisma-next/framework-components/control';\n\n/**\n * Classifies a codec `verifyType` hook finding into the target-neutral\n * categories the framework grades. A storage type is a named type instance\n * (e.g. a native enum); the only shape divergence it can carry is a change\n * to its value set, so a paired mismatch always classifies as `valueDrift`.\n */\nexport function classifyStorageTypeDiffIssue(issue: SchemaDiffIssue): VerifierIssueCategory {\n if (issue.reason === 'not-found') {\n return 'declaredMissing';\n }\n if (issue.reason === 'not-expected') {\n return 'extraAuxiliary';\n }\n return 'valueDrift';\n}\n\nexport function verifierDisposition(\n controlPolicy: ControlPolicy,\n issue: SchemaDiffIssue,\n): VerifierOutcome {\n return dispositionForCategory(controlPolicy, classifyStorageTypeDiffIssue(issue));\n}\n","/**\n * The differ-based SQL schema verify: post-diff filters and verdict.\n *\n * The generic node differ (`diffSchemas`) reports every node-level\n * difference between the derived expected tree and the introspected actual\n * tree. This module is the consumer side the spec assigns to the SQL\n * family: strict-mode extras gating and control-policy disposition are\n * reason/kind-keyed filters applied AFTER the diff — never inside it — and\n * the verify verdict derives from the filtered issue list.\n *\n * `verifySqlSchemaByDiff` wraps the verdict in the issue-based result\n * envelope — this is THE SQL schema verify (the legacy relational walk and\n * its verification tree are retired).\n */\n\nimport type { Contract, ControlPolicy } from '@prisma-next/contract/types';\nimport { effectiveControlPolicy } from '@prisma-next/contract/types';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n DiffSubjectGranularity,\n SchemaDiffIssue,\n VerifierIssueCategory,\n VerifierOutcome,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport { dispositionForCategory } from '@prisma-next/framework-components/control';\nimport { isStorageTypeInstance, type SqlStorage } from '@prisma-next/sql-contract/types';\nimport { RelationalSchemaNodeKind, type SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { extractCodecControlHooks } from '../assembly';\nimport type { SqlSchemaDiffFn } from '../migrations/schema-differ';\nimport type { CodecControlHooks } from '../migrations/types';\nimport { verifierDisposition } from './verifier-disposition';\n\n// ============================================================================\n// Subject-granularity classification — nodeKind → framework-neutral granularity\n// ============================================================================\n\nfunction issueNode(issue: SchemaDiffIssue): SqlSchemaIRNode | undefined {\n const node = issue.expected ?? issue.actual;\n if (node === undefined) return undefined;\n return blindCast<\n SqlSchemaIRNode,\n 'every node in a SQL schema diff tree is a SqlSchemaIRNode; nodeKind is its identity'\n >(node);\n}\n\n/**\n * Resolves an issue's framework-neutral {@link DiffSubjectGranularity} on\n * demand, from the issue's node's `nodeKind` via the target-provided\n * `granularityOf` map. The node carries only its `nodeKind` identity, never a\n * classification, and nothing is stamped onto the issue — every consumer\n * (the family verdict below, the framework aggregate's unclaimed-elements\n * sweep via {@link import('@prisma-next/framework-components/control').SchemaSubjectClassifierCapable})\n * calls this the same way, resolved by the family/target that owns the node\n * vocabulary. `undefined` for an issue with no node.\n */\nexport function classifyDiffSubjectGranularity(\n issue: SchemaDiffIssue,\n granularityOf: (nodeKind: string) => DiffSubjectGranularity,\n): DiffSubjectGranularity | undefined {\n const node = issueNode(issue);\n return node === undefined ? undefined : granularityOf(node.nodeKind);\n}\n\n/**\n * Resolves an issue's storage `entityKind` on demand, from the issue's\n * node's `nodeKind` via the target-provided `entityKindOf` map — the sibling\n * of {@link classifyDiffSubjectGranularity}, called the same way by the same\n * consumers (via\n * {@link import('@prisma-next/framework-components/control').SchemaSubjectClassifierCapable}).\n * `undefined` for an issue with no node, or for a node kind with no storage\n * entity of its own.\n */\nexport function classifyDiffEntityKind(\n issue: SchemaDiffIssue,\n entityKindOf: (nodeKind: string) => string | undefined,\n): string | undefined {\n const node = issueNode(issue);\n return node === undefined ? undefined : entityKindOf(node.nodeKind);\n}\n\n// ============================================================================\n// Issue classification — subject granularity + reason → target-neutral category\n// ============================================================================\n\n/**\n * Re-keys the legacy `classifySqlVerifierIssueKind` category mapping on the\n * issue's {@link DiffSubjectGranularity} (resolved via `granularityOf`) + the\n * issue reason. The vocabulary maps one-to-one: an undeclared live entity or\n * namespace is `extraTopLevelObject`, an undeclared live field\n * `extraNestedElement`, undeclared auxiliaries (constraints, indexes,\n * defaults) and structural leaves (policies) `extraAuxiliary`; a value-set\n * drift on a check node is `valueDrift`; every other paired divergence is\n * `declaredIncompatible`; anything the database lacks is `declaredMissing`.\n * `granularityOf` is the target's classifier, so target and extension node\n * kinds classify without the family importing them.\n */\nexport function classifySqlDiffIssue(\n issue: SchemaDiffIssue,\n granularityOf: (nodeKind: string) => DiffSubjectGranularity,\n): VerifierIssueCategory {\n if (issue.reason === 'not-found') {\n return 'declaredMissing';\n }\n if (issue.reason === 'not-expected') {\n const granularity = classifyDiffSubjectGranularity(issue, granularityOf);\n if (granularity === 'entity' || granularity === 'namespace') {\n return 'extraTopLevelObject';\n }\n if (granularity === 'field') {\n return 'extraNestedElement';\n }\n return 'extraAuxiliary';\n }\n if (issueNode(issue)?.nodeKind === RelationalSchemaNodeKind.check) {\n return 'valueDrift';\n }\n return 'declaredIncompatible';\n}\n\n/**\n * Whether a `not-expected` issue is a strict-mode-only finding. The legacy\n * walk detected every relational extra (namespaces, entities, fields, and\n * their auxiliaries) only under `--strict`; the structural diff (roots, RLS\n * policies, roles) was never strict-gated — its extras fail in both modes.\n * Keyed on the issue's granularity, resolved via `granularityOf`.\n */\nfunction isStrictOnlyExtra(\n issue: SchemaDiffIssue,\n granularityOf: (nodeKind: string) => DiffSubjectGranularity,\n): boolean {\n const granularity = classifyDiffSubjectGranularity(issue, granularityOf);\n return (\n granularity === 'namespace' ||\n granularity === 'entity' ||\n granularity === 'field' ||\n granularity === 'auxiliary'\n );\n}\n\n// ============================================================================\n// The post-diff filter + verdict\n// ============================================================================\n\nexport interface SqlDiffVerdictInput {\n /** The full, ownership-scoped diff issue list from the target's differ. */\n readonly issues: readonly SchemaDiffIssue[];\n /** Resolves a diff issue's subject table's declared control policy directly from the contract. */\n readonly resolveControlPolicy: (issue: SchemaDiffIssue) => ControlPolicy | undefined;\n readonly strict: boolean;\n readonly defaultControlPolicy: ControlPolicy | undefined;\n /** The target's classifier: a diff issue node's `nodeKind` → its subject granularity. */\n readonly granularityOf: (nodeKind: string) => DiffSubjectGranularity;\n}\n\nexport interface SqlDiffVerdict {\n readonly failures: readonly SchemaDiffIssue[];\n readonly warnings: readonly SchemaDiffIssue[];\n}\n\n/**\n * Applies the two consumer filters to a diff issue list: strict gating\n * (relational `not-expected` findings drop in lenient mode) and\n * control-policy disposition (each surviving issue grades against its\n * subject table's effective policy; suppressed issues drop, `observed`\n * subjects warn). The verify verdict is `failures.length === 0`.\n */\nexport function computeSqlDiffVerdict(input: SqlDiffVerdictInput): SqlDiffVerdict {\n const failures: SchemaDiffIssue[] = [];\n const warnings: SchemaDiffIssue[] = [];\n for (const issue of input.issues) {\n if (\n !input.strict &&\n issue.reason === 'not-expected' &&\n isStrictOnlyExtra(issue, input.granularityOf)\n ) {\n continue;\n }\n const tablePolicy = input.resolveControlPolicy(issue);\n const policy = effectiveControlPolicy(tablePolicy, input.defaultControlPolicy);\n const disposition: VerifierOutcome = dispositionForCategory(\n policy,\n classifySqlDiffIssue(issue, input.granularityOf),\n );\n if (disposition === 'suppress') continue;\n if (disposition === 'warn') {\n warnings.push(issue);\n continue;\n }\n failures.push(issue);\n }\n return { failures, warnings };\n}\n\n// ============================================================================\n// Storage-types check — the codec verifyType hook path\n// ============================================================================\n\nexport interface StorageTypeVerdictInput {\n readonly contract: Contract<SqlStorage>;\n /**\n * Expected/actual namespace-node pairs the target's differ input produced:\n * for a namespaced tree, one entry per expected namespace with a\n * non-empty table set, paired by DDL schema name (absent actual side for\n * a schema the database lacks); a flat tree is the sole pair.\n */\n readonly namespacePairs: ReadonlyArray<{\n readonly actual: SqlSchemaIRNode | undefined;\n }>;\n readonly codecHooks: ReadonlyMap<string, CodecControlHooks>;\n}\n\n/**\n * Runs the codec `verifyType` hooks the way the legacy walk did: once per\n * contract namespace with tables, against that namespace's paired actual\n * node (the hook reads namespace-scoped state such as `enums` off it).\n * Issue dispositions grade against the contract default policy, matching\n * the legacy `pushTypeNode` semantics.\n */\nexport interface StorageTypeVerdict {\n readonly failures: readonly SchemaDiffIssue[];\n readonly warnings: readonly SchemaDiffIssue[];\n}\n\nexport function computeStorageTypeVerdict(input: StorageTypeVerdictInput): StorageTypeVerdict {\n const failures: SchemaDiffIssue[] = [];\n const warnings: SchemaDiffIssue[] = [];\n const policy = effectiveControlPolicy(undefined, input.contract.defaultControlPolicy);\n for (const pair of input.namespacePairs) {\n if (pair.actual === undefined) continue;\n for (const [typeName, typeInstance] of Object.entries(input.contract.storage.types ?? {})) {\n if (!isStorageTypeInstance(typeInstance)) continue;\n const hook = input.codecHooks.get(typeInstance.codecId);\n if (!hook?.verifyType) continue;\n const typeIssues = hook.verifyType({ typeName, typeInstance, schema: pair.actual });\n for (const issue of typeIssues) {\n const disposition = verifierDisposition(policy, issue);\n if (disposition === 'suppress') continue;\n if (disposition === 'warn') {\n warnings.push(issue);\n continue;\n }\n failures.push(issue);\n }\n }\n }\n return { failures, warnings };\n}\n\n// ============================================================================\n// The issue-based verify envelope\n// ============================================================================\n\nexport interface VerifySqlSchemaByDiffInput {\n readonly contract: Contract<SqlStorage>;\n readonly schema: SqlSchemaIRNode;\n readonly strict: boolean;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n /** The target's full-tree node diff (`diffSchema` descriptor hook). */\n readonly diffSchema: SqlSchemaDiffFn;\n /** The target's classifier: a diff issue node's `nodeKind` → its subject granularity. */\n readonly granularityOf: (nodeKind: string) => DiffSubjectGranularity;\n}\n\n/**\n * THE SQL schema verify: runs the target's full-tree node diff, grades it\n * through the family's post-diff filters (strict gating + control-policy\n * disposition) plus the codec `verifyType` hook findings, and wraps the\n * verdict in the issue-based result envelope. `ok` holds exactly when both\n * issue lists are empty — the lists carry the verdict's failures.\n */\nexport function verifySqlSchemaByDiff(\n input: VerifySqlSchemaByDiffInput,\n): VerifyDatabaseSchemaResult {\n const startTime = Date.now();\n const verdictDiff = input.diffSchema({\n contract: input.contract,\n schema: input.schema,\n frameworkComponents: input.frameworkComponents,\n });\n const diffVerdict = computeSqlDiffVerdict({\n issues: verdictDiff.issues,\n resolveControlPolicy: verdictDiff.resolveControlPolicy,\n strict: input.strict,\n defaultControlPolicy: input.contract.defaultControlPolicy,\n granularityOf: input.granularityOf,\n });\n const storageTypeVerdict = computeStorageTypeVerdict({\n contract: input.contract,\n namespacePairs: verdictDiff.namespacePairs,\n codecHooks: extractCodecControlHooks(input.frameworkComponents),\n });\n const failCount = diffVerdict.failures.length + storageTypeVerdict.failures.length;\n const ok = failCount === 0;\n const profileHash =\n 'profileHash' in input.contract && typeof input.contract.profileHash === 'string'\n ? input.contract.profileHash\n : undefined;\n return {\n ok,\n ...(ok ? {} : { code: 'PN-SCHEMA-0001' }),\n summary: ok\n ? 'Database schema satisfies contract'\n : `Database schema does not satisfy contract (${failCount} failure${failCount === 1 ? '' : 's'})`,\n contract: {\n storageHash: input.contract.storage.storageHash,\n ...ifDefined('profileHash', profileHash),\n },\n target: {\n expected: input.contract.target,\n actual: input.contract.target,\n },\n schema: {\n issues: [...diffVerdict.failures, ...storageTypeVerdict.failures],\n warnings: {\n issues: [...diffVerdict.warnings, ...storageTypeVerdict.warnings],\n },\n },\n meta: { strict: input.strict },\n timings: { total: Date.now() - startTime },\n };\n}\n"],"mappings":"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"}
|
|
@@ -75,9 +75,8 @@ interface CodecControlHooks<TTargetDetails = unknown> {
|
|
|
75
75
|
* `SqlSchemaIR` class) because the actual value handed in is whatever
|
|
76
76
|
* per-namespace node the calling target's tree shape produces — a flat
|
|
77
77
|
* `SqlSchemaIR` for SQLite, a `PostgresNamespaceSchemaNode` for Postgres —
|
|
78
|
-
* read structurally for its `tables`/`
|
|
79
|
-
*
|
|
80
|
-
* `PostgresNamespaceSchemaNode.is(schema)`.
|
|
78
|
+
* read structurally for its `tables`/`nativeEnums` fields. Hooks that need
|
|
79
|
+
* the concrete Postgres shape narrow via `PostgresNamespaceSchemaNode.is(schema)`.
|
|
81
80
|
*/
|
|
82
81
|
planTypeOperations?: (options: {
|
|
83
82
|
readonly typeName: string;
|
|
@@ -232,12 +231,12 @@ interface SqlMigrationPlan<TTargetDetails> extends MigrationPlan {
|
|
|
232
231
|
}
|
|
233
232
|
type SqlPlannerConflictKind = 'typeMismatch' | 'nullabilityConflict' | 'indexIncompatible' | 'foreignKeyConflict' | 'missingButNonAdditive' | 'unsupportedOperation' | 'controlPolicySuppressedCall';
|
|
234
233
|
interface SqlPlannerConflictLocation {
|
|
235
|
-
readonly
|
|
236
|
-
readonly
|
|
234
|
+
readonly namespaceId?: string;
|
|
235
|
+
readonly entityKind?: string;
|
|
236
|
+
readonly entityName?: string;
|
|
237
237
|
readonly column?: string;
|
|
238
238
|
readonly index?: string;
|
|
239
239
|
readonly constraint?: string;
|
|
240
|
-
readonly type?: string;
|
|
241
240
|
}
|
|
242
241
|
interface SqlPlannerConflict extends MigrationPlannerConflict {
|
|
243
242
|
readonly kind: SqlPlannerConflictKind;
|
|
@@ -412,4 +411,4 @@ interface CreateSqlMigrationPlanOptions<TTargetDetails> {
|
|
|
412
411
|
}
|
|
413
412
|
//#endregion
|
|
414
413
|
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 };
|
|
415
|
-
//# sourceMappingURL=types-
|
|
414
|
+
//# sourceMappingURL=types-9DnjnhkE.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-9DnjnhkE.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.63",
|
|
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.63",
|
|
10
|
+
"@prisma-next/emitter": "0.14.0-dev.63",
|
|
11
|
+
"@prisma-next/framework-components": "0.14.0-dev.63",
|
|
12
|
+
"@prisma-next/migration-tools": "0.14.0-dev.63",
|
|
13
|
+
"@prisma-next/operations": "0.14.0-dev.63",
|
|
14
|
+
"@prisma-next/sql-contract": "0.14.0-dev.63",
|
|
15
|
+
"@prisma-next/sql-contract-emitter": "0.14.0-dev.63",
|
|
16
|
+
"@prisma-next/sql-contract-ts": "0.14.0-dev.63",
|
|
17
|
+
"@prisma-next/sql-operations": "0.14.0-dev.63",
|
|
18
|
+
"@prisma-next/sql-relational-core": "0.14.0-dev.63",
|
|
19
|
+
"@prisma-next/sql-runtime": "0.14.0-dev.63",
|
|
20
|
+
"@prisma-next/sql-schema-ir": "0.14.0-dev.63",
|
|
21
|
+
"@prisma-next/utils": "0.14.0-dev.63",
|
|
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.63",
|
|
26
|
+
"@prisma-next/psl-parser": "0.14.0-dev.63",
|
|
27
|
+
"@prisma-next/psl-printer": "0.14.0-dev.63",
|
|
28
|
+
"@prisma-next/sql-contract-psl": "0.14.0-dev.63",
|
|
29
|
+
"@prisma-next/test-utils": "0.14.0-dev.63",
|
|
30
|
+
"@prisma-next/tsconfig": "0.14.0-dev.63",
|
|
31
|
+
"@prisma-next/tsdown": "0.14.0-dev.63",
|
|
32
32
|
"tsdown": "0.22.1",
|
|
33
33
|
"typescript": "5.9.3",
|
|
34
34
|
"vitest": "4.1.8"
|
|
@@ -215,9 +215,9 @@ export interface StorageTypeVerdictInput {
|
|
|
215
215
|
/**
|
|
216
216
|
* Runs the codec `verifyType` hooks the way the legacy walk did: once per
|
|
217
217
|
* contract namespace with tables, against that namespace's paired actual
|
|
218
|
-
* node (the hook reads namespace-scoped state such as
|
|
219
|
-
*
|
|
220
|
-
*
|
|
218
|
+
* node (the hook reads namespace-scoped state such as `enums` off it).
|
|
219
|
+
* Issue dispositions grade against the contract default policy, matching
|
|
220
|
+
* the legacy `pushTypeNode` semantics.
|
|
221
221
|
*/
|
|
222
222
|
export interface StorageTypeVerdict {
|
|
223
223
|
readonly failures: readonly SchemaDiffIssue[];
|
|
@@ -5,20 +5,25 @@ import {
|
|
|
5
5
|
} from '@prisma-next/contract/types';
|
|
6
6
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
7
7
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
8
|
-
import type { SqlPlannerConflict } from './types';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* The target object a control policy governs for a single planner call,
|
|
12
11
|
* resolved from the target's own IR. `undefined` means the call's target
|
|
13
12
|
* object could not be positively established — a fail-closed signal: any
|
|
14
13
|
* policy stricter than `managed` drops such a call rather than emitting it.
|
|
14
|
+
*
|
|
15
|
+
* The object identity is a generic storage coordinate — `(entityKind,
|
|
16
|
+
* entityName)`, absent for a whole-namespace subject — never a target-specific
|
|
17
|
+
* `table`/`typeName` field. The family reasons about the coordinate for policy
|
|
18
|
+
* and deduplication; the target owns any vocabulary (table vs enum) when it
|
|
19
|
+
* renders a suppression.
|
|
15
20
|
*/
|
|
16
21
|
export interface ControlPolicySubject {
|
|
17
22
|
readonly namespaceId: string;
|
|
18
|
-
readonly
|
|
19
|
-
readonly
|
|
23
|
+
readonly entityKind?: string;
|
|
24
|
+
readonly entityName?: string;
|
|
20
25
|
readonly column?: string;
|
|
21
|
-
readonly
|
|
26
|
+
readonly explicitNodeControlPolicy?: ControlPolicy;
|
|
22
27
|
/**
|
|
23
28
|
* Whether the call creates a whole, previously-absent top-level storage
|
|
24
29
|
* object (e.g. a table or an enum/type), as opposed to modifying an
|
|
@@ -29,6 +34,26 @@ export interface ControlPolicySubject {
|
|
|
29
34
|
readonly createsNewObject: boolean;
|
|
30
35
|
}
|
|
31
36
|
|
|
37
|
+
/**
|
|
38
|
+
* The structured record a control-policy partition emits for one suppressed
|
|
39
|
+
* subject or call. It carries only raw data — no strings, no vocabulary — so
|
|
40
|
+
* the consumer (the target) renders the user-facing message itself:
|
|
41
|
+
*
|
|
42
|
+
* - `subject` — the suppressed subject (its coordinate + namespace), or
|
|
43
|
+
* `undefined` when the subject could not be resolved (fail-closed).
|
|
44
|
+
* - `policy` — the effective control policy that caused the suppression.
|
|
45
|
+
* - `factoryName` — the resolved creation factory name if the suppressed thing
|
|
46
|
+
* was a whole-object creation (e.g. `createTable`), else `undefined`. The
|
|
47
|
+
* family never invents a verb for a modification that produced no call.
|
|
48
|
+
* - `createsNewObject` — whether the suppressed thing was object creation.
|
|
49
|
+
*/
|
|
50
|
+
export interface SuppressionRecord {
|
|
51
|
+
readonly subject: ControlPolicySubject | undefined;
|
|
52
|
+
readonly policy: ControlPolicy;
|
|
53
|
+
readonly factoryName: string | undefined;
|
|
54
|
+
readonly createsNewObject: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
32
57
|
/**
|
|
33
58
|
* The control policy that governs a single call. The `external` default is an
|
|
34
59
|
* un-overridable namespace floor: when the contract default is `external`, no
|
|
@@ -71,67 +96,10 @@ function callAllowedUnderControlPolicy(
|
|
|
71
96
|
}
|
|
72
97
|
}
|
|
73
98
|
|
|
74
|
-
function defaultSubjectLabel(
|
|
75
|
-
factoryName: string,
|
|
76
|
-
subject: ControlPolicySubject | undefined,
|
|
77
|
-
): string {
|
|
78
|
-
if (subject?.table) {
|
|
79
|
-
return `${factoryName}(${subject.table})`;
|
|
80
|
-
}
|
|
81
|
-
if (subject?.typeName) {
|
|
82
|
-
return `${factoryName}(${subject.typeName})`;
|
|
83
|
-
}
|
|
84
|
-
return factoryName;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function suppressionSummary(
|
|
88
|
-
subjectLabel: string,
|
|
89
|
-
subject: ControlPolicySubject | undefined,
|
|
90
|
-
effectivePolicy: ControlPolicy,
|
|
91
|
-
): string {
|
|
92
|
-
const namespace = subject?.namespaceId ?? 'unknown';
|
|
93
|
-
const declared = subject?.explicitNodeControlPolicy;
|
|
94
|
-
if (effectivePolicy === 'external' && declared === 'managed') {
|
|
95
|
-
return `control policy suppressed: ${subjectLabel} — namespace '${namespace}' has effective control 'external' but table declared 'managed'`;
|
|
96
|
-
}
|
|
97
|
-
const declaredSuffix = declared ? ` but table declared '${declared}'` : '';
|
|
98
|
-
return `control policy suppressed: ${subjectLabel} — namespace '${namespace}' has effective control '${effectivePolicy}'${declaredSuffix}`;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function buildSubjectSuppressionWarning(
|
|
102
|
-
subject: ControlPolicySubject | undefined,
|
|
103
|
-
effectivePolicy: ControlPolicy,
|
|
104
|
-
factoryName: string,
|
|
105
|
-
formatSubjectLabel: (factoryName: string, subject: ControlPolicySubject | undefined) => string,
|
|
106
|
-
): SqlPlannerConflict {
|
|
107
|
-
const subjectLabel = formatSubjectLabel(factoryName, subject);
|
|
108
|
-
return {
|
|
109
|
-
kind: 'controlPolicySuppressedCall',
|
|
110
|
-
summary: suppressionSummary(subjectLabel, subject, effectivePolicy),
|
|
111
|
-
location: {
|
|
112
|
-
...ifDefined('namespace', subject?.namespaceId),
|
|
113
|
-
...ifDefined('table', subject?.table),
|
|
114
|
-
...ifDefined('column', subject?.column),
|
|
115
|
-
...ifDefined('type', subject?.typeName),
|
|
116
|
-
},
|
|
117
|
-
meta: {
|
|
118
|
-
controlPolicy: effectivePolicy,
|
|
119
|
-
factoryName,
|
|
120
|
-
...ifDefined('declaredControlPolicy', subject?.explicitNodeControlPolicy),
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function defaultModificationFactoryNameForSubject(subject: ControlPolicySubject): string {
|
|
126
|
-
if (subject.table) return 'alterTable';
|
|
127
|
-
if (subject.typeName) return 'alterType';
|
|
128
|
-
return 'alterSchema';
|
|
129
|
-
}
|
|
130
|
-
|
|
131
99
|
/**
|
|
132
100
|
* Partition the calls produced for a single set of subjects into those the
|
|
133
101
|
* effective control policy permits (`kept`) and a list of
|
|
134
|
-
* {@link
|
|
102
|
+
* {@link SuppressionRecord}s describing the suppressed calls.
|
|
135
103
|
*
|
|
136
104
|
* **Prefer {@link partitionIssuesByControlPolicy}** for the schema-issue
|
|
137
105
|
* pipeline: it filters subjects out of the planner's *input* so the planner
|
|
@@ -146,18 +114,13 @@ export function partitionCallsByControlPolicy<TCall>(options: {
|
|
|
146
114
|
readonly contract: Contract<SqlStorage>;
|
|
147
115
|
readonly resolveControlPolicySubject: (call: TCall) => ControlPolicySubject | undefined;
|
|
148
116
|
readonly resolveFactoryName: (call: TCall) => string;
|
|
149
|
-
readonly formatSubjectLabel?: (
|
|
150
|
-
factoryName: string,
|
|
151
|
-
subject: ControlPolicySubject | undefined,
|
|
152
|
-
) => string;
|
|
153
117
|
}): {
|
|
154
118
|
readonly kept: readonly TCall[];
|
|
155
|
-
readonly
|
|
119
|
+
readonly suppressions: readonly SuppressionRecord[];
|
|
156
120
|
} {
|
|
157
121
|
const defaultControlPolicy = options.contract.defaultControlPolicy;
|
|
158
|
-
const formatSubjectLabel = options.formatSubjectLabel ?? defaultSubjectLabel;
|
|
159
122
|
const kept: TCall[] = [];
|
|
160
|
-
const
|
|
123
|
+
const suppressions: SuppressionRecord[] = [];
|
|
161
124
|
|
|
162
125
|
for (const call of options.calls) {
|
|
163
126
|
const subject = options.resolveControlPolicySubject(call);
|
|
@@ -165,16 +128,18 @@ export function partitionCallsByControlPolicy<TCall>(options: {
|
|
|
165
128
|
if (callAllowedUnderControlPolicy(policy, subject)) {
|
|
166
129
|
kept.push(call);
|
|
167
130
|
} else {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
131
|
+
suppressions.push({
|
|
132
|
+
subject,
|
|
133
|
+
policy,
|
|
134
|
+
factoryName: options.resolveFactoryName(call),
|
|
135
|
+
createsNewObject: subject?.createsNewObject ?? false,
|
|
136
|
+
});
|
|
172
137
|
}
|
|
173
138
|
}
|
|
174
139
|
|
|
175
140
|
return Object.freeze({
|
|
176
141
|
kept: Object.freeze(kept),
|
|
177
|
-
|
|
142
|
+
suppressions: Object.freeze(suppressions),
|
|
178
143
|
});
|
|
179
144
|
}
|
|
180
145
|
|
|
@@ -192,18 +157,15 @@ export function partitionCallsByControlPolicy<TCall>(options: {
|
|
|
192
157
|
* cannot reason about the live shape of a subject the user marked as
|
|
193
158
|
* out-of-scope (`external`).
|
|
194
159
|
*
|
|
195
|
-
* `
|
|
196
|
-
* suppressed issue). `factoryName` is
|
|
197
|
-
*
|
|
198
|
-
* the
|
|
199
|
-
*
|
|
200
|
-
* `defaultModificationFactoryName(subject)` — a synthetic label that names
|
|
201
|
-
* the *kind* of mutation that would have run, since no concrete DDL call was
|
|
202
|
-
* generated.
|
|
160
|
+
* `suppressions` is one {@link SuppressionRecord} per suppressed subject (not
|
|
161
|
+
* per suppressed issue). Its `factoryName` is the creation factory name when any
|
|
162
|
+
* of the subject's issues is whole-object creation (e.g. `createTable`), else
|
|
163
|
+
* `undefined` — the family never invents a modification verb for an op that
|
|
164
|
+
* produced no call; the target renders the message.
|
|
203
165
|
*
|
|
204
166
|
* Unresolved-subject issues (`resolveControlPolicySubject` returns
|
|
205
|
-
* `undefined`) emit one
|
|
206
|
-
*
|
|
167
|
+
* `undefined`) emit one record each; they cannot be deduplicated because they
|
|
168
|
+
* carry no subject coordinate.
|
|
207
169
|
*/
|
|
208
170
|
export function partitionIssuesByControlPolicy<TIssue>(options: {
|
|
209
171
|
readonly issues: readonly TIssue[];
|
|
@@ -221,34 +183,19 @@ export function partitionIssuesByControlPolicy<TIssue>(options: {
|
|
|
221
183
|
*
|
|
222
184
|
* 1. Under `tolerated`, only issues whose `resolveCreationFactoryName`
|
|
223
185
|
* returns a value flow into the planner (create-if-absent).
|
|
224
|
-
* 2.
|
|
225
|
-
*
|
|
226
|
-
* otherwise they fall back to `defaultModificationFactoryName`.
|
|
186
|
+
* 2. A suppressed subject's record carries the resolved creation factoryName
|
|
187
|
+
* when it has at least one creation-flavoured issue, else `undefined`.
|
|
227
188
|
*/
|
|
228
189
|
readonly resolveCreationFactoryName: (issue: TIssue) => string | undefined;
|
|
229
|
-
/**
|
|
230
|
-
* Default modification factoryName for a suppressed subject whose issues
|
|
231
|
-
* are all non-creation (the subject exists but has a different shape).
|
|
232
|
-
* Defaults to `'alterTable'` / `'alterType'` / `'alterSchema'` based on the
|
|
233
|
-
* subject's populated coordinates.
|
|
234
|
-
*/
|
|
235
|
-
readonly defaultModificationFactoryName?: (subject: ControlPolicySubject) => string;
|
|
236
|
-
readonly formatSubjectLabel?: (
|
|
237
|
-
factoryName: string,
|
|
238
|
-
subject: ControlPolicySubject | undefined,
|
|
239
|
-
) => string;
|
|
240
190
|
}): {
|
|
241
191
|
readonly plannable: readonly TIssue[];
|
|
242
|
-
readonly
|
|
192
|
+
readonly suppressions: readonly SuppressionRecord[];
|
|
243
193
|
} {
|
|
244
194
|
const defaultControlPolicy = options.contract.defaultControlPolicy;
|
|
245
|
-
const formatSubjectLabel = options.formatSubjectLabel ?? defaultSubjectLabel;
|
|
246
|
-
const inferModificationFactoryName =
|
|
247
|
-
options.defaultModificationFactoryName ?? defaultModificationFactoryNameForSubject;
|
|
248
195
|
|
|
249
196
|
const plannable: TIssue[] = [];
|
|
250
197
|
// Resolved-subject suppressions are deduplicated by subject key so we emit
|
|
251
|
-
// one
|
|
198
|
+
// one record per suppressed subject, not one per suppressed issue.
|
|
252
199
|
// `creationFactoryName` upgrades from `undefined` to a concrete creation
|
|
253
200
|
// name the first time we see a creation-flavoured issue for the subject.
|
|
254
201
|
const suppressedSubjects = new Map<
|
|
@@ -259,7 +206,7 @@ export function partitionIssuesByControlPolicy<TIssue>(options: {
|
|
|
259
206
|
creationFactoryName?: string;
|
|
260
207
|
}
|
|
261
208
|
>();
|
|
262
|
-
const unresolvedSuppressions:
|
|
209
|
+
const unresolvedSuppressions: SuppressionRecord[] = [];
|
|
263
210
|
|
|
264
211
|
for (const issue of options.issues) {
|
|
265
212
|
const subject = options.resolveControlPolicySubject(issue);
|
|
@@ -281,10 +228,12 @@ export function partitionIssuesByControlPolicy<TIssue>(options: {
|
|
|
281
228
|
}
|
|
282
229
|
|
|
283
230
|
if (subject === undefined) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
231
|
+
unresolvedSuppressions.push({
|
|
232
|
+
subject: undefined,
|
|
233
|
+
policy,
|
|
234
|
+
factoryName: creationFactoryName,
|
|
235
|
+
createsNewObject: false,
|
|
236
|
+
});
|
|
288
237
|
continue;
|
|
289
238
|
}
|
|
290
239
|
|
|
@@ -303,20 +252,22 @@ export function partitionIssuesByControlPolicy<TIssue>(options: {
|
|
|
303
252
|
}
|
|
304
253
|
}
|
|
305
254
|
|
|
306
|
-
const
|
|
255
|
+
const suppressions: SuppressionRecord[] = [...unresolvedSuppressions];
|
|
307
256
|
for (const entry of suppressedSubjects.values()) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
257
|
+
suppressions.push({
|
|
258
|
+
subject: entry.subject,
|
|
259
|
+
policy: entry.policy,
|
|
260
|
+
factoryName: entry.creationFactoryName,
|
|
261
|
+
createsNewObject: entry.subject.createsNewObject,
|
|
262
|
+
});
|
|
312
263
|
}
|
|
313
264
|
|
|
314
265
|
return Object.freeze({
|
|
315
266
|
plannable: Object.freeze(plannable),
|
|
316
|
-
|
|
267
|
+
suppressions: Object.freeze(suppressions),
|
|
317
268
|
});
|
|
318
269
|
}
|
|
319
270
|
|
|
320
271
|
function subjectKey(subject: ControlPolicySubject): string {
|
|
321
|
-
return `${subject.namespaceId}\u0000${subject.
|
|
272
|
+
return `${subject.namespaceId}\u0000${subject.entityKind ?? ''}\u0000${subject.entityName ?? ''}`;
|
|
322
273
|
}
|
|
@@ -104,9 +104,8 @@ export interface CodecControlHooks<TTargetDetails = unknown> {
|
|
|
104
104
|
* `SqlSchemaIR` class) because the actual value handed in is whatever
|
|
105
105
|
* per-namespace node the calling target's tree shape produces — a flat
|
|
106
106
|
* `SqlSchemaIR` for SQLite, a `PostgresNamespaceSchemaNode` for Postgres —
|
|
107
|
-
* read structurally for its `tables`/`
|
|
108
|
-
*
|
|
109
|
-
* `PostgresNamespaceSchemaNode.is(schema)`.
|
|
107
|
+
* read structurally for its `tables`/`nativeEnums` fields. Hooks that need
|
|
108
|
+
* the concrete Postgres shape narrow via `PostgresNamespaceSchemaNode.is(schema)`.
|
|
110
109
|
*/
|
|
111
110
|
planTypeOperations?: (options: {
|
|
112
111
|
readonly typeName: string;
|
|
@@ -283,12 +282,12 @@ export type SqlPlannerConflictKind =
|
|
|
283
282
|
| 'controlPolicySuppressedCall';
|
|
284
283
|
|
|
285
284
|
export interface SqlPlannerConflictLocation {
|
|
286
|
-
readonly
|
|
287
|
-
readonly
|
|
285
|
+
readonly namespaceId?: string;
|
|
286
|
+
readonly entityKind?: string;
|
|
287
|
+
readonly entityName?: string;
|
|
288
288
|
readonly column?: string;
|
|
289
289
|
readonly index?: string;
|
|
290
290
|
readonly constraint?: string;
|
|
291
|
-
readonly type?: string;
|
|
292
291
|
}
|
|
293
292
|
|
|
294
293
|
export interface SqlPlannerConflict extends MigrationPlannerConflict {
|
package/src/exports/control.ts
CHANGED
|
@@ -31,7 +31,7 @@ export {
|
|
|
31
31
|
detectDestructiveChanges,
|
|
32
32
|
resolveValueSetValues,
|
|
33
33
|
} from '../core/migrations/contract-to-schema-ir';
|
|
34
|
-
export type { ControlPolicySubject } from '../core/migrations/control-policy';
|
|
34
|
+
export type { ControlPolicySubject, SuppressionRecord } from '../core/migrations/control-policy';
|
|
35
35
|
export {
|
|
36
36
|
controlPolicyForCall,
|
|
37
37
|
partitionCallsByControlPolicy,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-COTsneBU.d.mts","names":[],"sources":["../src/core/migrations/types.ts"],"mappings":"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"}
|