@prisma-next/family-sql 0.14.0-dev.39 → 0.14.0-dev.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contract-to-schema-ir-S-evq8E6.mjs +264 -0
- package/dist/contract-to-schema-ir-S-evq8E6.mjs.map +1 -0
- package/dist/{control-adapter-B2q9WN1V.d.mts → control-adapter-DHYFuOBy.d.mts} +14 -17
- package/dist/{control-adapter-B2q9WN1V.d.mts.map → control-adapter-DHYFuOBy.d.mts.map} +1 -1
- package/dist/control-adapter.d.mts +1 -1
- package/dist/control.d.mts +17 -2
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +42 -943
- package/dist/control.mjs.map +1 -1
- package/dist/{schema-verify.d.mts → diff.d.mts} +4 -4
- package/dist/diff.d.mts.map +1 -0
- package/dist/{verify-sql-schema-CEY7b78t.mjs → diff.mjs} +154 -244
- package/dist/diff.mjs.map +1 -0
- package/dist/migration.d.mts +1 -1
- package/dist/psl-infer.d.mts +80 -0
- package/dist/psl-infer.d.mts.map +1 -0
- package/dist/psl-infer.mjs +334 -0
- package/dist/psl-infer.mjs.map +1 -0
- package/dist/{verify-sql-schema-B8uEjw2s.d.mts → sql-schema-diff-6z36dZt6.d.mts} +43 -4
- package/dist/sql-schema-diff-6z36dZt6.d.mts.map +1 -0
- package/dist/{types-BxsFkHYv.d.mts → types-CkOIJXxU.d.mts} +83 -16
- package/dist/types-CkOIJXxU.d.mts.map +1 -0
- package/package.json +23 -22
- package/src/core/control-adapter.ts +12 -24
- package/src/core/control-instance.ts +113 -45
- package/src/core/{schema-verify/verify-sql-schema.ts → diff/sql-schema-diff.ts} +196 -8
- package/src/core/{schema-verify → diff}/verify-helpers.ts +12 -0
- package/src/core/migrations/contract-to-schema-ir.ts +48 -13
- package/src/core/migrations/field-event-planner.ts +3 -8
- package/src/core/migrations/schema-differ.ts +40 -0
- package/src/core/migrations/types.ts +43 -2
- package/src/core/psl-contract-infer/printer-config.ts +0 -6
- package/src/exports/control.ts +1 -0
- package/src/exports/diff.ts +18 -0
- package/src/exports/psl-infer.ts +36 -0
- package/dist/schema-verify.d.mts.map +0 -1
- package/dist/schema-verify.mjs +0 -2
- package/dist/types-BxsFkHYv.d.mts.map +0 -1
- package/dist/verify-sql-schema-B8uEjw2s.d.mts.map +0 -1
- package/dist/verify-sql-schema-CEY7b78t.mjs.map +0 -1
- package/src/core/psl-contract-infer/postgres-default-mapping.ts +0 -16
- package/src/core/psl-contract-infer/postgres-type-map.ts +0 -157
- package/src/core/psl-contract-infer/sql-schema-ir-to-psl-ast.ts +0 -795
- package/src/exports/schema-verify.ts +0 -18
- /package/src/core/{schema-verify → diff}/control-verify-emit.ts +0 -0
- /package/src/core/{schema-verify → diff}/verifier-disposition.ts +0 -0
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.40",
|
|
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.40",
|
|
10
|
+
"@prisma-next/emitter": "0.14.0-dev.40",
|
|
11
|
+
"@prisma-next/framework-components": "0.14.0-dev.40",
|
|
12
|
+
"@prisma-next/migration-tools": "0.14.0-dev.40",
|
|
13
|
+
"@prisma-next/operations": "0.14.0-dev.40",
|
|
14
|
+
"@prisma-next/sql-contract": "0.14.0-dev.40",
|
|
15
|
+
"@prisma-next/sql-contract-emitter": "0.14.0-dev.40",
|
|
16
|
+
"@prisma-next/sql-contract-ts": "0.14.0-dev.40",
|
|
17
|
+
"@prisma-next/sql-operations": "0.14.0-dev.40",
|
|
18
|
+
"@prisma-next/sql-relational-core": "0.14.0-dev.40",
|
|
19
|
+
"@prisma-next/sql-runtime": "0.14.0-dev.40",
|
|
20
|
+
"@prisma-next/sql-schema-ir": "0.14.0-dev.40",
|
|
21
|
+
"@prisma-next/utils": "0.14.0-dev.40",
|
|
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.40",
|
|
26
|
+
"@prisma-next/psl-parser": "0.14.0-dev.40",
|
|
27
|
+
"@prisma-next/psl-printer": "0.14.0-dev.40",
|
|
28
|
+
"@prisma-next/sql-contract-psl": "0.14.0-dev.40",
|
|
29
|
+
"@prisma-next/test-utils": "0.14.0-dev.40",
|
|
30
|
+
"@prisma-next/tsconfig": "0.14.0-dev.40",
|
|
31
|
+
"@prisma-next/tsdown": "0.14.0-dev.40",
|
|
32
32
|
"tsdown": "0.22.1",
|
|
33
33
|
"typescript": "5.9.3",
|
|
34
34
|
"vitest": "4.1.8"
|
|
@@ -48,11 +48,12 @@
|
|
|
48
48
|
"exports": {
|
|
49
49
|
"./control": "./dist/control.mjs",
|
|
50
50
|
"./control-adapter": "./dist/control-adapter.mjs",
|
|
51
|
+
"./diff": "./dist/diff.mjs",
|
|
51
52
|
"./ir": "./dist/ir.mjs",
|
|
52
53
|
"./migration": "./dist/migration.mjs",
|
|
53
54
|
"./pack": "./dist/pack.mjs",
|
|
55
|
+
"./psl-infer": "./dist/psl-infer.mjs",
|
|
54
56
|
"./runtime": "./dist/runtime.mjs",
|
|
55
|
-
"./schema-verify": "./dist/schema-verify.mjs",
|
|
56
57
|
"./verify": "./dist/verify.mjs",
|
|
57
58
|
"./package.json": "./package.json"
|
|
58
59
|
},
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Contract,
|
|
3
|
-
ContractMarkerRecord,
|
|
4
|
-
LedgerEntryRecord,
|
|
5
|
-
} from '@prisma-next/contract/types';
|
|
1
|
+
import type { ContractMarkerRecord, LedgerEntryRecord } from '@prisma-next/contract/types';
|
|
6
2
|
import type {
|
|
7
3
|
ControlAdapterInstance,
|
|
8
4
|
ControlStack,
|
|
9
|
-
SchemaDiffIssue,
|
|
10
5
|
} from '@prisma-next/framework-components/control';
|
|
11
|
-
import type { SqlControlDriverInstance
|
|
6
|
+
import type { SqlControlDriverInstance } from '@prisma-next/sql-contract/types';
|
|
12
7
|
import type {
|
|
13
8
|
AnyQueryAst,
|
|
14
9
|
DdlNode,
|
|
@@ -16,8 +11,8 @@ import type {
|
|
|
16
11
|
LowererContext,
|
|
17
12
|
SqlExecuteRequest,
|
|
18
13
|
} from '@prisma-next/sql-relational-core/ast';
|
|
19
|
-
import type {
|
|
20
|
-
import type { DefaultNormalizer, NativeTypeNormalizer } from './
|
|
14
|
+
import type { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
15
|
+
import type { DefaultNormalizer, NativeTypeNormalizer } from './diff/sql-schema-diff';
|
|
21
16
|
|
|
22
17
|
/**
|
|
23
18
|
* Structural interface for anything that can lower a SQL/DDL AST node to a
|
|
@@ -162,22 +157,27 @@ export interface SqlControlAdapter<TTarget extends string = string>
|
|
|
162
157
|
): Promise<void>;
|
|
163
158
|
|
|
164
159
|
/**
|
|
165
|
-
* Introspects a database schema and returns
|
|
160
|
+
* Introspects a database schema and returns the target's schema-IR node.
|
|
166
161
|
*
|
|
167
162
|
* This is a pure schema discovery operation that queries the database catalog
|
|
168
163
|
* and returns the schema structure without type mapping or contract enrichment.
|
|
169
164
|
* Type mapping and enrichment are handled separately by enrichment helpers.
|
|
170
165
|
*
|
|
166
|
+
* The return type is the family-base `SqlSchemaIRNode` so each target returns
|
|
167
|
+
* its own node shape: SQLite returns a flat `SqlSchemaIR`, Postgres returns a
|
|
168
|
+
* `PostgresDatabaseSchemaNode` tree root. Consumers `ensure` the concrete
|
|
169
|
+
* target type before walking it.
|
|
170
|
+
*
|
|
171
171
|
* @param driver - ControlDriverInstance instance for executing queries (target-specific)
|
|
172
172
|
* @param contract - Optional contract for contract-guided introspection (filtering, optimization)
|
|
173
173
|
* @param schema - Schema name to introspect (defaults to 'public')
|
|
174
|
-
* @returns Promise resolving to
|
|
174
|
+
* @returns Promise resolving to the live database schema node
|
|
175
175
|
*/
|
|
176
176
|
introspect(
|
|
177
177
|
driver: SqlControlDriverInstance<TTarget>,
|
|
178
178
|
contract?: unknown,
|
|
179
179
|
schema?: string,
|
|
180
|
-
): Promise<
|
|
180
|
+
): Promise<SqlSchemaIRNode>;
|
|
181
181
|
|
|
182
182
|
/**
|
|
183
183
|
* Optional target-specific normalizer for raw database default expressions.
|
|
@@ -193,18 +193,6 @@ export interface SqlControlAdapter<TTarget extends string = string>
|
|
|
193
193
|
*/
|
|
194
194
|
readonly normalizeNativeType?: NativeTypeNormalizer;
|
|
195
195
|
|
|
196
|
-
/**
|
|
197
|
-
* Optional hook for collecting target-specific diff issues during schema
|
|
198
|
-
* verification. Called after the relational SQL verification pass; returns
|
|
199
|
-
* generic `SchemaDiffIssue[]` (coordinate + outcome + message — no target
|
|
200
|
-
* naming) that are folded into `VerifyDatabaseSchemaResult.schema.schemaDiffIssues`
|
|
201
|
-
* and counted as failures when non-empty.
|
|
202
|
-
*/
|
|
203
|
-
collectSchemaDiffIssues?(
|
|
204
|
-
contract: Contract<SqlStorage>,
|
|
205
|
-
schema: SqlSchemaIR,
|
|
206
|
-
): readonly SchemaDiffIssue[];
|
|
207
|
-
|
|
208
196
|
/**
|
|
209
197
|
* Ordered DDL queries that bootstrap marker/ledger control tables for migration
|
|
210
198
|
* runners. Postgres includes `CREATE SCHEMA`; SQLite does not.
|
|
@@ -44,18 +44,17 @@ import type {
|
|
|
44
44
|
SqlExecuteRequest,
|
|
45
45
|
} from '@prisma-next/sql-relational-core/ast';
|
|
46
46
|
import { defaultIndexName } from '@prisma-next/sql-schema-ir/naming';
|
|
47
|
-
import type {
|
|
47
|
+
import type { SqlSchemaIRNode, SqlTableIR } from '@prisma-next/sql-schema-ir/types';
|
|
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
51
|
import { SqlContractSerializer } from './ir/sql-contract-serializer';
|
|
52
|
+
import type { DiffDatabaseSchemaInput } from './migrations/schema-differ';
|
|
52
53
|
import type {
|
|
53
54
|
SqlControlAdapterDescriptor,
|
|
54
55
|
SqlControlExtensionDescriptor,
|
|
55
56
|
} from './migrations/types';
|
|
56
57
|
import { sqlOperationsToPreview } from './operation-preview';
|
|
57
|
-
import { sqlSchemaIrToPslAst } from './psl-contract-infer/sql-schema-ir-to-psl-ast';
|
|
58
|
-
import { verifySqlSchema } from './schema-verify/verify-sql-schema';
|
|
59
58
|
import { collectSupportedCodecTypeIds } from './verify';
|
|
60
59
|
|
|
61
60
|
function extractCodecTypeIdsFromContract(contract: unknown): readonly string[] {
|
|
@@ -192,9 +191,9 @@ interface SqlFamilyInstanceState {
|
|
|
192
191
|
}
|
|
193
192
|
|
|
194
193
|
export interface SqlControlFamilyInstance
|
|
195
|
-
extends ControlFamilyInstance<'sql',
|
|
196
|
-
SchemaViewCapable<
|
|
197
|
-
PslContractInferCapable<
|
|
194
|
+
extends ControlFamilyInstance<'sql', SqlSchemaIRNode>,
|
|
195
|
+
SchemaViewCapable<SqlSchemaIRNode>,
|
|
196
|
+
PslContractInferCapable<SqlSchemaIRNode>,
|
|
198
197
|
OperationPreviewCapable,
|
|
199
198
|
SqlFamilyInstanceState {
|
|
200
199
|
/**
|
|
@@ -216,18 +215,17 @@ export interface SqlControlFamilyInstance
|
|
|
216
215
|
}): Promise<VerifyDatabaseResult>;
|
|
217
216
|
|
|
218
217
|
/**
|
|
219
|
-
* Verify a contract against an already-introspected schema
|
|
218
|
+
* Verify a contract against an already-introspected schema.
|
|
220
219
|
*
|
|
221
220
|
* Callers that need to verify against the live database compose
|
|
222
221
|
* `introspect({ driver })` + `verifySchema({ contract, schema, ... })`.
|
|
223
|
-
* The aggregate verifier
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
* as `extras`.
|
|
222
|
+
* The aggregate verifier hands in the full introspected schema and scopes
|
|
223
|
+
* the returned result to each member's contract space afterwards — so
|
|
224
|
+
* sibling-space tables never survive as `extras`.
|
|
227
225
|
*/
|
|
228
226
|
verifySchema(options: {
|
|
229
227
|
readonly contract: unknown;
|
|
230
|
-
readonly schema:
|
|
228
|
+
readonly schema: SqlSchemaIRNode;
|
|
231
229
|
readonly strict: boolean;
|
|
232
230
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
|
|
233
231
|
}): VerifyDatabaseSchemaResult;
|
|
@@ -242,9 +240,9 @@ export interface SqlControlFamilyInstance
|
|
|
242
240
|
introspect(options: {
|
|
243
241
|
readonly driver: SqlControlDriverInstance<string>;
|
|
244
242
|
readonly contract?: unknown;
|
|
245
|
-
}): Promise<
|
|
243
|
+
}): Promise<SqlSchemaIRNode>;
|
|
246
244
|
|
|
247
|
-
inferPslContract(schemaIR:
|
|
245
|
+
inferPslContract(schemaIR: SqlSchemaIRNode): PslDocumentAst;
|
|
248
246
|
|
|
249
247
|
lowerAst(
|
|
250
248
|
ast: AnyQueryAst | DdlNode,
|
|
@@ -300,8 +298,6 @@ export interface SqlControlFamilyInstance
|
|
|
300
298
|
|
|
301
299
|
bootstrapControlTableQueries(): readonly DdlNode[];
|
|
302
300
|
|
|
303
|
-
bootstrapSignMarkerQueries(): readonly DdlNode[];
|
|
304
|
-
|
|
305
301
|
toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview;
|
|
306
302
|
}
|
|
307
303
|
|
|
@@ -535,6 +531,31 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
535
531
|
};
|
|
536
532
|
}
|
|
537
533
|
).contractSerializer;
|
|
534
|
+
// Database→PSL inference is target logic (it owns the dialect type/default
|
|
535
|
+
// maps and walks its own schema tree), so it is read off the descriptor like
|
|
536
|
+
// `contractSerializer`. Absent for targets without `contract infer` (Mongo).
|
|
537
|
+
const targetInferPslContract = blindCast<
|
|
538
|
+
{ readonly inferPslContract?: (schema: SqlSchemaIRNode) => PslDocumentAst },
|
|
539
|
+
'reading the optional target-descriptor inferPslContract hook'
|
|
540
|
+
>(target).inferPslContract;
|
|
541
|
+
// The combined database-schema verify is a required target-descriptor
|
|
542
|
+
// operation: every SQL target provides it, wrapping the same comparison
|
|
543
|
+
// `diffDatabaseSchema` runs in the verify envelope plus the pass/warn/fail
|
|
544
|
+
// tree the CLI renders. Read it off the descriptor like the other
|
|
545
|
+
// target-owned hooks.
|
|
546
|
+
const verifyDatabaseSchema = blindCast<
|
|
547
|
+
{
|
|
548
|
+
readonly verifyDatabaseSchema?: (
|
|
549
|
+
input: DiffDatabaseSchemaInput,
|
|
550
|
+
) => VerifyDatabaseSchemaResult;
|
|
551
|
+
},
|
|
552
|
+
'reading the required target-descriptor verifyDatabaseSchema hook'
|
|
553
|
+
>(target).verifyDatabaseSchema;
|
|
554
|
+
if (!verifyDatabaseSchema) {
|
|
555
|
+
throw new Error(
|
|
556
|
+
`SQL target "${target.targetId}" is missing the required verifyDatabaseSchema descriptor operation`,
|
|
557
|
+
);
|
|
558
|
+
}
|
|
538
559
|
const deserializeWithTargetSerializer = (contractOrJson: unknown): Contract<SqlStorage> => {
|
|
539
560
|
const serializer = targetSerializer ?? new SqlContractSerializer();
|
|
540
561
|
const json =
|
|
@@ -687,29 +708,36 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
687
708
|
|
|
688
709
|
verifySchema(options: {
|
|
689
710
|
readonly contract: unknown;
|
|
690
|
-
readonly schema:
|
|
711
|
+
readonly schema: SqlSchemaIRNode;
|
|
691
712
|
readonly strict: boolean;
|
|
692
713
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
|
|
693
714
|
}): VerifyDatabaseSchemaResult {
|
|
694
715
|
const contract = deserializeWithTargetSerializer(options.contract) as Contract<SqlStorage>;
|
|
695
|
-
|
|
696
|
-
|
|
716
|
+
// Verify is a thin consumer of the target's black-box comparison: it
|
|
717
|
+
// introspects the actual schema (already in `options.schema`), calls the
|
|
718
|
+
// target's required `verifyDatabaseSchema`, and rejects when a surviving
|
|
719
|
+
// issue is a failure. It composes no diffing itself and is blind to how
|
|
720
|
+
// the comparison works.
|
|
721
|
+
const sqlResult = verifyDatabaseSchema({
|
|
697
722
|
contract,
|
|
698
723
|
schema: options.schema,
|
|
699
724
|
strict: options.strict,
|
|
700
725
|
typeMetadataRegistry,
|
|
701
726
|
frameworkComponents: options.frameworkComponents,
|
|
702
|
-
...ifDefined('normalizeDefault', controlAdapter.normalizeDefault),
|
|
703
|
-
...ifDefined('normalizeNativeType', controlAdapter.normalizeNativeType),
|
|
704
727
|
});
|
|
705
|
-
|
|
706
|
-
|
|
728
|
+
// Control-policy suppression of the structural (e.g. RLS policy) diff
|
|
729
|
+
// issues is a verify-side post-step — the combined diff returns them
|
|
730
|
+
// ownership-filtered, and a suppressed control policy drops them here.
|
|
707
731
|
const schemaDiffIssues = filterSchemaDiffIssues(
|
|
708
|
-
|
|
732
|
+
sqlResult.schema.schemaDiffIssues,
|
|
709
733
|
contract.defaultControlPolicy,
|
|
710
734
|
);
|
|
711
|
-
|
|
712
|
-
|
|
735
|
+
const relationalFails = sqlResult.schema.counts.fail;
|
|
736
|
+
if (schemaDiffIssues.length === 0) {
|
|
737
|
+
if (schemaDiffIssues === sqlResult.schema.schemaDiffIssues) return sqlResult;
|
|
738
|
+
return { ...sqlResult, schema: { ...sqlResult.schema, schemaDiffIssues } };
|
|
739
|
+
}
|
|
740
|
+
const totalFails = relationalFails + schemaDiffIssues.length;
|
|
713
741
|
return {
|
|
714
742
|
...sqlResult,
|
|
715
743
|
ok: false,
|
|
@@ -885,12 +913,17 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
885
913
|
async introspect(options: {
|
|
886
914
|
readonly driver: SqlControlDriverInstance<string>;
|
|
887
915
|
readonly contract?: unknown;
|
|
888
|
-
}): Promise<
|
|
916
|
+
}): Promise<SqlSchemaIRNode> {
|
|
889
917
|
return getControlAdapter().introspect(options.driver, options.contract);
|
|
890
918
|
},
|
|
891
919
|
|
|
892
|
-
inferPslContract(schemaIR:
|
|
893
|
-
|
|
920
|
+
inferPslContract(schemaIR: SqlSchemaIRNode): PslDocumentAst {
|
|
921
|
+
if (!targetInferPslContract) {
|
|
922
|
+
throw new Error(
|
|
923
|
+
`Target "${target.targetId}" does not support contract infer (no inferPslContract on its descriptor).`,
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
return targetInferPslContract(schemaIR);
|
|
894
927
|
},
|
|
895
928
|
|
|
896
929
|
lowerAst(
|
|
@@ -904,17 +937,52 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
904
937
|
return getControlAdapter().bootstrapControlTableQueries();
|
|
905
938
|
},
|
|
906
939
|
|
|
907
|
-
bootstrapSignMarkerQueries(): readonly DdlNode[] {
|
|
908
|
-
return getControlAdapter().bootstrapSignMarkerQueries();
|
|
909
|
-
},
|
|
910
|
-
|
|
911
940
|
toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview {
|
|
912
941
|
return sqlOperationsToPreview(operations);
|
|
913
942
|
},
|
|
914
943
|
|
|
915
|
-
toSchemaView(schema:
|
|
916
|
-
|
|
917
|
-
|
|
944
|
+
toSchemaView(schema: SqlSchemaIRNode): CoreSchemaView {
|
|
945
|
+
// Walk the schema-IR tree's own structure (root → namespaces → tables)
|
|
946
|
+
// into one flat list of table nodes. A root that exposes a `namespaces`
|
|
947
|
+
// record (Postgres) contributes each namespace's tables; a flat root
|
|
948
|
+
// (SQLite) is its own single namespace. The single-schema common case
|
|
949
|
+
// renders the same table-level view as today — no synthetic namespace
|
|
950
|
+
// level.
|
|
951
|
+
const root = blindCast<
|
|
952
|
+
{
|
|
953
|
+
readonly namespaces?: Readonly<
|
|
954
|
+
Record<string, { readonly tables: Record<string, SqlTableIR> }>
|
|
955
|
+
>;
|
|
956
|
+
readonly tables?: Record<string, SqlTableIR>;
|
|
957
|
+
},
|
|
958
|
+
'structural read of the schema-IR tree own namespaces/tables records'
|
|
959
|
+
>(schema);
|
|
960
|
+
// A multi-namespace root qualifies every table's display name with its
|
|
961
|
+
// namespace key, so same-named tables in different namespaces (e.g.
|
|
962
|
+
// public.thing and auth.thing) render distinct ids and labels. The
|
|
963
|
+
// single-namespace case (and a flat SQLite root) keeps today's bare
|
|
964
|
+
// names. Synthesized constraint/index fallback names keep the bare table
|
|
965
|
+
// name — that is the name the database derives them from.
|
|
966
|
+
const namespaceEntries: ReadonlyArray<[string | undefined, Record<string, SqlTableIR>]> =
|
|
967
|
+
root.namespaces !== undefined
|
|
968
|
+
? Object.entries(root.namespaces).map(
|
|
969
|
+
([namespaceKey, namespace]): [string, Record<string, SqlTableIR>] => [
|
|
970
|
+
namespaceKey,
|
|
971
|
+
namespace.tables,
|
|
972
|
+
],
|
|
973
|
+
)
|
|
974
|
+
: [[undefined, root.tables ?? {}]];
|
|
975
|
+
const qualify = namespaceEntries.length > 1;
|
|
976
|
+
const tableEntries: ReadonlyArray<[string, string, SqlTableIR]> = namespaceEntries.flatMap(
|
|
977
|
+
([namespaceKey, tables]) =>
|
|
978
|
+
Object.entries(tables).map(([tableName, table]): [string, string, SqlTableIR] => [
|
|
979
|
+
qualify && namespaceKey !== undefined ? `${namespaceKey}.${tableName}` : tableName,
|
|
980
|
+
tableName,
|
|
981
|
+
table,
|
|
982
|
+
]),
|
|
983
|
+
);
|
|
984
|
+
const tableNodes: readonly SchemaTreeNode[] = tableEntries.map(
|
|
985
|
+
([displayName, tableName, table]: [string, string, SqlTableIR]) => {
|
|
918
986
|
const children: SchemaTreeNode[] = [];
|
|
919
987
|
|
|
920
988
|
const columnNodes: SchemaTreeNode[] = [];
|
|
@@ -925,7 +993,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
925
993
|
columnNodes.push(
|
|
926
994
|
new SchemaTreeNode({
|
|
927
995
|
kind: 'field',
|
|
928
|
-
id: `column-${
|
|
996
|
+
id: `column-${displayName}-${columnName}`,
|
|
929
997
|
label,
|
|
930
998
|
meta: {
|
|
931
999
|
nativeType: column.nativeType,
|
|
@@ -940,7 +1008,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
940
1008
|
children.push(
|
|
941
1009
|
new SchemaTreeNode({
|
|
942
1010
|
kind: 'collection',
|
|
943
|
-
id: `columns-${
|
|
1011
|
+
id: `columns-${displayName}`,
|
|
944
1012
|
label: 'columns',
|
|
945
1013
|
children: columnNodes,
|
|
946
1014
|
}),
|
|
@@ -952,7 +1020,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
952
1020
|
children.push(
|
|
953
1021
|
new SchemaTreeNode({
|
|
954
1022
|
kind: 'index',
|
|
955
|
-
id: `primary-key-${
|
|
1023
|
+
id: `primary-key-${displayName}`,
|
|
956
1024
|
label: `primary key: ${pkColumns}`,
|
|
957
1025
|
meta: {
|
|
958
1026
|
columns: table.primaryKey.columns,
|
|
@@ -968,7 +1036,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
968
1036
|
children.push(
|
|
969
1037
|
new SchemaTreeNode({
|
|
970
1038
|
kind: 'index',
|
|
971
|
-
id: `unique-${
|
|
1039
|
+
id: `unique-${displayName}-${name}`,
|
|
972
1040
|
label,
|
|
973
1041
|
meta: {
|
|
974
1042
|
columns: unique.columns,
|
|
@@ -984,7 +1052,7 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
984
1052
|
children.push(
|
|
985
1053
|
new SchemaTreeNode({
|
|
986
1054
|
kind: 'index',
|
|
987
|
-
id: `index-${
|
|
1055
|
+
id: `index-${displayName}-${name}`,
|
|
988
1056
|
label,
|
|
989
1057
|
meta: {
|
|
990
1058
|
columns: index.columns,
|
|
@@ -1012,8 +1080,8 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
1012
1080
|
|
|
1013
1081
|
return new SchemaTreeNode({
|
|
1014
1082
|
kind: 'entity',
|
|
1015
|
-
id: `table-${
|
|
1016
|
-
label: `table ${
|
|
1083
|
+
id: `table-${displayName}`,
|
|
1084
|
+
label: `table ${displayName}`,
|
|
1017
1085
|
...(Object.keys(tableMeta).length > 0 ? { meta: tableMeta } : {}),
|
|
1018
1086
|
...(children.length > 0 ? { children } : {}),
|
|
1019
1087
|
});
|
|
@@ -1033,8 +1101,8 @@ export function createSqlFamilyInstance<TTargetId extends string>(
|
|
|
1033
1101
|
}
|
|
1034
1102
|
|
|
1035
1103
|
/**
|
|
1036
|
-
* Filters schema
|
|
1037
|
-
* contract's `defaultControlPolicy`. Issues whose outcome maps to a suppressed
|
|
1104
|
+
* Filters the structural schema-diff issues (from `diffDatabaseSchema`) through
|
|
1105
|
+
* the contract's `defaultControlPolicy`. Issues whose outcome maps to a suppressed
|
|
1038
1106
|
* category under the effective policy are removed. This mirrors the control-policy
|
|
1039
1107
|
* filtering applied by `verifySqlSchema` for table/column-level findings.
|
|
1040
1108
|
*
|