@prisma-next/target-postgres 0.15.0-dev.13 → 0.15.0-dev.2
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-policy-DaLdbcYE.mjs → control-policy-1Tcf7Tyu.mjs} +72 -41
- package/dist/control-policy-1Tcf7Tyu.mjs.map +1 -0
- package/dist/control.mjs +3 -3
- package/dist/{diff-database-schema-oY3brcLj.mjs → diff-database-schema-Bfgshz4v.mjs} +22 -85
- package/dist/diff-database-schema-Bfgshz4v.mjs.map +1 -0
- package/dist/diff-database-schema.d.mts +12 -3
- package/dist/diff-database-schema.d.mts.map +1 -1
- package/dist/diff-database-schema.mjs +1 -1
- package/dist/issue-planner.d.mts +1 -1
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.d.mts +2 -2
- package/dist/migration.mjs +2 -2
- package/dist/{op-factory-call-CvH0JeBW.d.mts → op-factory-call-Bn9zDx4_.d.mts} +4 -7
- package/dist/op-factory-call-Bn9zDx4_.d.mts.map +1 -0
- package/dist/{op-factory-call-tBcLo_B8.mjs → op-factory-call-C38NzvQD.mjs} +12 -33
- package/dist/op-factory-call-C38NzvQD.mjs.map +1 -0
- package/dist/op-factory-call.d.mts +2 -2
- package/dist/op-factory-call.mjs +2 -2
- package/dist/{planner-ootbxGty.mjs → planner-BvUu6b9C.mjs} +11 -11
- package/dist/planner-BvUu6b9C.mjs.map +1 -0
- package/dist/{planner-produced-postgres-migration-k33bb9Sm.d.mts → planner-produced-postgres-migration-BEY1T0Xm.d.mts} +2 -2
- package/dist/{planner-produced-postgres-migration-k33bb9Sm.d.mts.map → planner-produced-postgres-migration-BEY1T0Xm.d.mts.map} +1 -1
- package/dist/{planner-produced-postgres-migration-DVsaobdV.mjs → planner-produced-postgres-migration-D7y-PEHK.mjs} +2 -2
- package/dist/{planner-produced-postgres-migration-DVsaobdV.mjs.map → planner-produced-postgres-migration-D7y-PEHK.mjs.map} +1 -1
- package/dist/planner-produced-postgres-migration.d.mts +1 -1
- package/dist/planner-produced-postgres-migration.mjs +1 -1
- package/dist/planner.d.mts +2 -2
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +2 -2
- package/dist/{postgres-database-schema-node-DJOTywwQ.d.mts → postgres-database-schema-node-CJv5bfbs.d.mts} +2 -11
- package/dist/postgres-database-schema-node-CJv5bfbs.d.mts.map +1 -0
- package/dist/{postgres-migration-ulfqRGA1.d.mts → postgres-migration-DbckK1su.d.mts} +2 -27
- package/dist/postgres-migration-DbckK1su.d.mts.map +1 -0
- package/dist/{postgres-migration-Bt3sXoID.mjs → postgres-migration-arMSWU9b.mjs} +2 -18
- package/dist/postgres-migration-arMSWU9b.mjs.map +1 -0
- package/dist/{postgres-role-schema-node-bg32e7I-.mjs → postgres-role-schema-node-Cm-j0ZGM.mjs} +2 -3
- package/dist/postgres-role-schema-node-Cm-j0ZGM.mjs.map +1 -0
- package/dist/types.d.mts +2 -3
- package/dist/types.mjs +3 -3
- package/package.json +20 -20
- package/src/core/migrations/contract-to-postgres-database-schema-node.ts +19 -99
- package/src/core/migrations/control-policy.ts +3 -4
- package/src/core/migrations/diff-database-schema.ts +3 -3
- package/src/core/migrations/issue-planner.ts +80 -41
- package/src/core/migrations/op-factory-call.ts +14 -38
- package/src/core/migrations/planner-strategies.ts +4 -5
- package/src/core/migrations/planner.ts +4 -5
- package/src/core/migrations/postgres-migration.ts +0 -60
- package/src/core/migrations/verify-postgres-namespaces.ts +1 -0
- package/src/core/schema-ir/postgres-policy-schema-node.ts +2 -12
- package/src/exports/op-factory-call.ts +0 -5
- package/src/exports/types.ts +0 -1
- package/dist/control-policy-DaLdbcYE.mjs.map +0 -1
- package/dist/diff-database-schema-oY3brcLj.mjs.map +0 -1
- package/dist/op-factory-call-CvH0JeBW.d.mts.map +0 -1
- package/dist/op-factory-call-tBcLo_B8.mjs.map +0 -1
- package/dist/planner-ootbxGty.mjs.map +0 -1
- package/dist/postgres-database-schema-node-DJOTywwQ.d.mts.map +0 -1
- package/dist/postgres-migration-Bt3sXoID.mjs.map +0 -1
- package/dist/postgres-migration-ulfqRGA1.d.mts.map +0 -1
- package/dist/postgres-role-schema-node-bg32e7I-.mjs.map +0 -1
- package/dist/schema-node-kinds-CrYzCR1i.d.mts +0 -30
- package/dist/schema-node-kinds-CrYzCR1i.d.mts.map +0 -1
|
@@ -25,7 +25,6 @@ import type {
|
|
|
25
25
|
} from '@prisma-next/family-sql/control';
|
|
26
26
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
27
27
|
import type { DiffableNode, SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
28
|
-
import { issueOutcome, orderIssuesByDependencies } from '@prisma-next/framework-components/control';
|
|
29
28
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
30
29
|
import type { SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
31
30
|
import type { DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
|
|
@@ -137,7 +136,6 @@ export interface IssuePlannerValue {
|
|
|
137
136
|
type CallCategory =
|
|
138
137
|
| 'dep'
|
|
139
138
|
| 'drop'
|
|
140
|
-
| 'dropType'
|
|
141
139
|
| 'table'
|
|
142
140
|
| 'rlsEnable'
|
|
143
141
|
| 'rlsPolicy'
|
|
@@ -153,13 +151,6 @@ type CallCategory =
|
|
|
153
151
|
* legacy walk-schema planner's emission order so `db init` and `db update`
|
|
154
152
|
* produce byte-identical plans for the shared shape (deps → drops → tables
|
|
155
153
|
* → columns → alters → PKs → uniques → indexes → FKs).
|
|
156
|
-
*
|
|
157
|
-
* `dropType` (DROP TYPE for a managed native enum) is its own bucket, ordered
|
|
158
|
-
* after the general drop bucket: a type can only be dropped once every table
|
|
159
|
-
* whose column uses it is gone. A column→enum edge would make this precise,
|
|
160
|
-
* but `coalesceSubtreeIssues` removes the column issue under a whole-table
|
|
161
|
-
* drop, so the edge never reaches the graph; the coarse bucket stands in until
|
|
162
|
-
* that edge lands (the coordinate work is a later slice).
|
|
163
154
|
*/
|
|
164
155
|
function classifyCall(call: PostgresOpFactoryCall): CallCategory {
|
|
165
156
|
switch (call.factoryName) {
|
|
@@ -168,9 +159,8 @@ function classifyCall(call: PostgresOpFactoryCall): CallCategory {
|
|
|
168
159
|
case 'createNativeEnumType':
|
|
169
160
|
case 'addNativeEnumValue':
|
|
170
161
|
return 'dep';
|
|
171
|
-
case 'dropNativeEnumType':
|
|
172
|
-
return 'dropType';
|
|
173
162
|
case 'dropTable':
|
|
163
|
+
case 'dropNativeEnumType':
|
|
174
164
|
case 'dropColumn':
|
|
175
165
|
case 'dropConstraint':
|
|
176
166
|
case 'dropCheckConstraint':
|
|
@@ -379,6 +369,57 @@ export function columnTypeChanged(expected: SqlColumnIR, actual: SqlColumnIR): b
|
|
|
379
369
|
);
|
|
380
370
|
}
|
|
381
371
|
|
|
372
|
+
// ----------------------------------------------------------------------------
|
|
373
|
+
// Node-keyed issue ordering (re-keys ISSUE_KIND_ORDER on nodeKind + reason)
|
|
374
|
+
// ----------------------------------------------------------------------------
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Re-keys the legacy `ISSUE_KIND_ORDER` on `(nodeKind, reason)`, numbers
|
|
378
|
+
* preserved so the dependency intent stays legible. Final emission order is
|
|
379
|
+
* fixed downstream by `classifyCall` bucketing (dep → drop → table → column →
|
|
380
|
+
* recipe → alter → primaryKey → unique → index → foreignKey), so this only
|
|
381
|
+
* breaks ties within a bucket.
|
|
382
|
+
*/
|
|
383
|
+
export function nodeIssueOrder(issue: SchemaDiffIssue): number {
|
|
384
|
+
const node = issueNode(issue);
|
|
385
|
+
if (node === undefined) return 99;
|
|
386
|
+
switch (node.nodeKind) {
|
|
387
|
+
case PostgresSchemaNodeKind.namespace:
|
|
388
|
+
return 1;
|
|
389
|
+
case PostgresSchemaNodeKind.nativeEnum:
|
|
390
|
+
// Creates order right after namespace creates within the 'dep' bucket
|
|
391
|
+
// (CREATE SCHEMA before CREATE TYPE); drops order after table drops
|
|
392
|
+
// within the 'drop' bucket (DROP TYPE only after its dependents left).
|
|
393
|
+
return issue.reason === 'not-expected' ? 17 : 2;
|
|
394
|
+
case RelationalSchemaNodeKind.foreignKey:
|
|
395
|
+
return issue.reason === 'not-expected' ? 10 : 60;
|
|
396
|
+
case RelationalSchemaNodeKind.unique:
|
|
397
|
+
return issue.reason === 'not-expected' ? 11 : 51;
|
|
398
|
+
case RelationalSchemaNodeKind.primaryKey:
|
|
399
|
+
return issue.reason === 'not-expected' ? 12 : 50;
|
|
400
|
+
case RelationalSchemaNodeKind.index:
|
|
401
|
+
return issue.reason === 'not-expected' ? 13 : 52;
|
|
402
|
+
case RelationalSchemaNodeKind.columnDefault:
|
|
403
|
+
if (issue.reason === 'not-expected') return 14;
|
|
404
|
+
return issue.reason === 'not-found' ? 42 : 43;
|
|
405
|
+
case RelationalSchemaNodeKind.column:
|
|
406
|
+
if (issue.reason === 'not-expected') return 15;
|
|
407
|
+
return issue.reason === 'not-found' ? 30 : 40;
|
|
408
|
+
case PostgresSchemaNodeKind.table:
|
|
409
|
+
return issue.reason === 'not-expected' ? 16 : 20;
|
|
410
|
+
case RelationalSchemaNodeKind.check:
|
|
411
|
+
if (issue.reason === 'not-found') return 53;
|
|
412
|
+
return issue.reason === 'not-expected' ? 55 : 54;
|
|
413
|
+
default:
|
|
414
|
+
return 99;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Deterministic tiebreak within an order bucket: the diff path already encodes schema → table → child. */
|
|
419
|
+
export function nodeIssueKey(issue: SchemaDiffIssue): string {
|
|
420
|
+
return issue.path.join(' ');
|
|
421
|
+
}
|
|
422
|
+
|
|
382
423
|
// ----------------------------------------------------------------------------
|
|
383
424
|
// Subtree coalescing (the planner's responsibility per the differ's contract)
|
|
384
425
|
// ----------------------------------------------------------------------------
|
|
@@ -396,7 +437,7 @@ export function coalesceSubtreeIssues<TNode extends DiffableNode = DiffableNode>
|
|
|
396
437
|
issues: readonly SchemaDiffIssue<TNode>[],
|
|
397
438
|
): readonly SchemaDiffIssue<TNode>[] {
|
|
398
439
|
const collapsingPaths = issues
|
|
399
|
-
.filter((issue) =>
|
|
440
|
+
.filter((issue) => issue.reason === 'not-found' || issue.reason === 'not-expected')
|
|
400
441
|
.map((issue) => issue.path);
|
|
401
442
|
if (collapsingPaths.length === 0) return issues;
|
|
402
443
|
return issues.filter(
|
|
@@ -560,14 +601,14 @@ function mapNativeEnumNodeIssue(
|
|
|
560
601
|
);
|
|
561
602
|
}
|
|
562
603
|
const schemaName = emissionSchemaName(ctx, ddlSchemaName);
|
|
563
|
-
if (
|
|
604
|
+
if (issue.reason === 'not-found') {
|
|
564
605
|
const expected = blindCast<
|
|
565
606
|
PostgresNativeEnumSchemaNode,
|
|
566
607
|
'a not-found native-enum issue always carries the expected PostgresNativeEnumSchemaNode'
|
|
567
608
|
>(issue.expected);
|
|
568
609
|
return ok([new CreateNativeEnumTypeCall(schemaName, expected.typeName, expected.members)]);
|
|
569
610
|
}
|
|
570
|
-
if (
|
|
611
|
+
if (issue.reason === 'not-expected') {
|
|
571
612
|
const actual = blindCast<
|
|
572
613
|
PostgresNativeEnumSchemaNode,
|
|
573
614
|
'a not-expected native-enum issue always carries the actual PostgresNativeEnumSchemaNode'
|
|
@@ -613,14 +654,14 @@ function mapTableNodeIssue(
|
|
|
613
654
|
ddlSchemaName: string,
|
|
614
655
|
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
615
656
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
616
|
-
if (
|
|
657
|
+
if (issue.reason === 'not-found') {
|
|
617
658
|
const table = blindCast<
|
|
618
659
|
PostgresTableSchemaNode,
|
|
619
660
|
'a not-found table issue always carries the expected PostgresTableSchemaNode'
|
|
620
661
|
>(issue.expected);
|
|
621
662
|
return ok(buildCreateTableCallsFromNode(schemaName, ddlSchemaName, table, codecHooks));
|
|
622
663
|
}
|
|
623
|
-
if (
|
|
664
|
+
if (issue.reason === 'not-expected') {
|
|
624
665
|
const table = blindCast<
|
|
625
666
|
PostgresTableSchemaNode,
|
|
626
667
|
'a not-expected table issue always carries the actual PostgresTableSchemaNode'
|
|
@@ -662,7 +703,7 @@ function mapColumnNodeIssue(
|
|
|
662
703
|
tableName: string,
|
|
663
704
|
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
664
705
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
665
|
-
if (
|
|
706
|
+
if (issue.reason === 'not-found') {
|
|
666
707
|
const column = blindCast<
|
|
667
708
|
SqlColumnIR,
|
|
668
709
|
'a not-found column issue always carries the expected column node'
|
|
@@ -671,7 +712,7 @@ function mapColumnNodeIssue(
|
|
|
671
712
|
new AddColumnCall(schemaName, tableName, renderColumnDdl(column.name, column, codecHooks)),
|
|
672
713
|
]);
|
|
673
714
|
}
|
|
674
|
-
if (
|
|
715
|
+
if (issue.reason === 'not-expected') {
|
|
675
716
|
const column = blindCast<
|
|
676
717
|
SqlColumnIR,
|
|
677
718
|
'a not-expected column issue always carries the actual column node'
|
|
@@ -714,7 +755,7 @@ function mapColumnDefaultNodeIssue(
|
|
|
714
755
|
tableName: string,
|
|
715
756
|
columnName: string,
|
|
716
757
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
717
|
-
if (
|
|
758
|
+
if (issue.reason === 'not-expected') {
|
|
718
759
|
return ok([new DropDefaultCall(schemaName, tableName, columnName)]);
|
|
719
760
|
}
|
|
720
761
|
// not-found (SET DEFAULT, additive) or not-equal (SET DEFAULT, widening).
|
|
@@ -731,7 +772,7 @@ function mapColumnDefaultNodeIssue(
|
|
|
731
772
|
tableName,
|
|
732
773
|
columnName,
|
|
733
774
|
defaultSql,
|
|
734
|
-
|
|
775
|
+
issue.reason === 'not-equal' ? 'widening' : 'additive',
|
|
735
776
|
),
|
|
736
777
|
]);
|
|
737
778
|
}
|
|
@@ -741,7 +782,7 @@ function mapPrimaryKeyNodeIssue(
|
|
|
741
782
|
schemaName: string,
|
|
742
783
|
tableName: string,
|
|
743
784
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
744
|
-
if (
|
|
785
|
+
if (issue.reason === 'not-found') {
|
|
745
786
|
const pk = blindCast<
|
|
746
787
|
{ readonly columns: readonly string[]; readonly name?: string },
|
|
747
788
|
'a not-found primary-key issue always carries the expected PrimaryKey node'
|
|
@@ -749,7 +790,7 @@ function mapPrimaryKeyNodeIssue(
|
|
|
749
790
|
const constraintName = pk.name ?? `${tableName}_pkey`;
|
|
750
791
|
return ok([new AddPrimaryKeyCall(schemaName, tableName, constraintName, [...pk.columns])]);
|
|
751
792
|
}
|
|
752
|
-
if (
|
|
793
|
+
if (issue.reason === 'not-expected') {
|
|
753
794
|
const pk = blindCast<
|
|
754
795
|
{ readonly name?: string },
|
|
755
796
|
'a not-expected primary-key issue always carries the actual PrimaryKey node'
|
|
@@ -766,14 +807,14 @@ function mapForeignKeyNodeIssue(
|
|
|
766
807
|
schemaName: string,
|
|
767
808
|
tableName: string,
|
|
768
809
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
769
|
-
if (
|
|
810
|
+
if (issue.reason === 'not-found') {
|
|
770
811
|
const fk = blindCast<
|
|
771
812
|
SqlForeignKeyIR,
|
|
772
813
|
'a not-found foreign-key issue always carries the expected foreign-key node'
|
|
773
814
|
>(issue.expected);
|
|
774
815
|
return ok([new AddForeignKeyCall(schemaName, tableName, fkSpecFromNode(fk, tableName))]);
|
|
775
816
|
}
|
|
776
|
-
if (
|
|
817
|
+
if (issue.reason === 'not-expected') {
|
|
777
818
|
const fk = blindCast<
|
|
778
819
|
SqlForeignKeyIR,
|
|
779
820
|
'a not-expected foreign-key issue always carries the actual foreign-key node'
|
|
@@ -789,7 +830,7 @@ function mapUniqueNodeIssue(
|
|
|
789
830
|
schemaName: string,
|
|
790
831
|
tableName: string,
|
|
791
832
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
792
|
-
if (
|
|
833
|
+
if (issue.reason === 'not-found') {
|
|
793
834
|
const unique = blindCast<
|
|
794
835
|
SqlUniqueIR,
|
|
795
836
|
'a not-found unique issue always carries the expected unique node'
|
|
@@ -797,7 +838,7 @@ function mapUniqueNodeIssue(
|
|
|
797
838
|
const name = unique.name ?? `${tableName}_${unique.columns.join('_')}_key`;
|
|
798
839
|
return ok([new AddUniqueCall(schemaName, tableName, name, [...unique.columns])]);
|
|
799
840
|
}
|
|
800
|
-
if (
|
|
841
|
+
if (issue.reason === 'not-expected') {
|
|
801
842
|
const unique = blindCast<
|
|
802
843
|
SqlUniqueIR,
|
|
803
844
|
'a not-expected unique issue always carries the actual unique node'
|
|
@@ -813,7 +854,7 @@ function mapIndexNodeIssue(
|
|
|
813
854
|
schemaName: string,
|
|
814
855
|
tableName: string,
|
|
815
856
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
816
|
-
if (
|
|
857
|
+
if (issue.reason === 'not-found') {
|
|
817
858
|
const index = blindCast<
|
|
818
859
|
SqlIndexIR,
|
|
819
860
|
'a not-found index issue always carries the expected index node'
|
|
@@ -824,7 +865,7 @@ function mapIndexNodeIssue(
|
|
|
824
865
|
if (index.options !== undefined) extras.options = index.options;
|
|
825
866
|
return ok([new CreateIndexCall(schemaName, tableName, indexName, [...index.columns], extras)]);
|
|
826
867
|
}
|
|
827
|
-
if (
|
|
868
|
+
if (issue.reason === 'not-expected') {
|
|
828
869
|
const index = blindCast<
|
|
829
870
|
SqlIndexIR,
|
|
830
871
|
'a not-expected index issue always carries the actual index node'
|
|
@@ -844,7 +885,7 @@ function mapCheckNodeIssue(
|
|
|
844
885
|
// the default mapper handles directly; check_missing / check_mismatch are
|
|
845
886
|
// consumed by `checkConstraintPlanCallStrategy` (drop+recreate), so reaching
|
|
846
887
|
// here for them means the strategy did not run — a conflict.
|
|
847
|
-
if (
|
|
888
|
+
if (issue.reason === 'not-expected') {
|
|
848
889
|
const check = blindCast<
|
|
849
890
|
{ readonly name: string },
|
|
850
891
|
'a not-expected check issue always carries the actual check node'
|
|
@@ -861,8 +902,8 @@ function mapCheckNodeIssue(
|
|
|
861
902
|
|
|
862
903
|
/**
|
|
863
904
|
* Maps one node-typed diff issue to its migration call(s), dispatching on the
|
|
864
|
-
* node's `nodeKind`
|
|
865
|
-
*
|
|
905
|
+
* node's `nodeKind` + `issue.reason`, reading nodes and resolving column DDL
|
|
906
|
+
* from `codecRef` via `column-ddl-rendering.ts`.
|
|
866
907
|
*/
|
|
867
908
|
export function mapNodeIssueToCall(
|
|
868
909
|
issue: SchemaDiffIssue,
|
|
@@ -878,7 +919,7 @@ export function mapNodeIssueToCall(
|
|
|
878
919
|
);
|
|
879
920
|
}
|
|
880
921
|
if (node.nodeKind === PostgresSchemaNodeKind.namespace) {
|
|
881
|
-
if (
|
|
922
|
+
if (issue.reason !== 'not-found') {
|
|
882
923
|
return notOk(
|
|
883
924
|
nodeConflict('unsupportedOperation', `Unexpected namespace drift: ${issue.path.join('/')}`),
|
|
884
925
|
);
|
|
@@ -1011,12 +1052,13 @@ export function planIssues(
|
|
|
1011
1052
|
}
|
|
1012
1053
|
}
|
|
1013
1054
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1055
|
+
const sorted = [...remaining].sort((a, b) => {
|
|
1056
|
+
const kindDelta = nodeIssueOrder(a) - nodeIssueOrder(b);
|
|
1057
|
+
if (kindDelta !== 0) return kindDelta;
|
|
1058
|
+
const keyA = nodeIssueKey(a);
|
|
1059
|
+
const keyB = nodeIssueKey(b);
|
|
1060
|
+
return keyA < keyB ? -1 : keyA > keyB ? 1 : 0;
|
|
1061
|
+
});
|
|
1020
1062
|
|
|
1021
1063
|
const defaultCalls: PostgresOpFactoryCall[] = [];
|
|
1022
1064
|
const conflicts: SqlPlannerConflict[] = [];
|
|
@@ -1064,9 +1106,6 @@ export function planIssues(
|
|
|
1064
1106
|
const calls: PostgresOpFactoryCall[] = [
|
|
1065
1107
|
...byCategory('dep'),
|
|
1066
1108
|
...byCategory('drop'),
|
|
1067
|
-
// DROP TYPE after every table drop — a managed enum type can only go once
|
|
1068
|
-
// no live column still uses it.
|
|
1069
|
-
...byCategory('dropType'),
|
|
1070
1109
|
...byCategory('table'),
|
|
1071
1110
|
...byCategory('column'),
|
|
1072
1111
|
...gatedRecipe,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
tableExistsAst,
|
|
46
46
|
} from '../../contract-free/checks';
|
|
47
47
|
import * as contractFreeDdl from '../../contract-free/ddl';
|
|
48
|
-
import type { PostgresRlsPolicy
|
|
48
|
+
import type { PostgresRlsPolicy } from '../postgres-rls-policy';
|
|
49
49
|
import {
|
|
50
50
|
escapeLiteral,
|
|
51
51
|
quoteIdentifier,
|
|
@@ -740,6 +740,10 @@ export class AddNotNullColumnDirectCall extends PostgresOpFactoryCallNode {
|
|
|
740
740
|
renderTypeScript(): string {
|
|
741
741
|
return `rawSql(${jsonToTsSource({ id: `column.${this.tableName}.${this.columnName}`, label: this.label, operationClass: 'additive' })})`;
|
|
742
742
|
}
|
|
743
|
+
|
|
744
|
+
override importRequirements(): readonly ImportRequirement[] {
|
|
745
|
+
return [];
|
|
746
|
+
}
|
|
743
747
|
}
|
|
744
748
|
|
|
745
749
|
/**
|
|
@@ -806,6 +810,10 @@ export class AddNotNullColumnWithTempDefaultCall extends PostgresOpFactoryCallNo
|
|
|
806
810
|
renderTypeScript(): string {
|
|
807
811
|
return `rawSql(${jsonToTsSource({ id: `column.${this.tableName}.${this.columnName}`, label: this.label, operationClass: 'additive' })})`;
|
|
808
812
|
}
|
|
813
|
+
|
|
814
|
+
override importRequirements(): readonly ImportRequirement[] {
|
|
815
|
+
return [];
|
|
816
|
+
}
|
|
809
817
|
}
|
|
810
818
|
|
|
811
819
|
// ============================================================================
|
|
@@ -1584,23 +1592,7 @@ export class CreatePostgresRlsPolicyCall extends PostgresOpFactoryCallNode {
|
|
|
1584
1592
|
}
|
|
1585
1593
|
|
|
1586
1594
|
renderTypeScript(): string {
|
|
1587
|
-
|
|
1588
|
-
const input: PostgresRlsPolicyInput = {
|
|
1589
|
-
name: p.name,
|
|
1590
|
-
prefix: p.prefix,
|
|
1591
|
-
tableName: p.tableName,
|
|
1592
|
-
namespaceId: p.namespaceId,
|
|
1593
|
-
operation: p.operation,
|
|
1594
|
-
roles: p.roles,
|
|
1595
|
-
...ifDefined('using', p.using),
|
|
1596
|
-
...ifDefined('withCheck', p.withCheck),
|
|
1597
|
-
permissive: p.permissive,
|
|
1598
|
-
};
|
|
1599
|
-
return `this.createRlsPolicy({ schema: ${jsonToTsSource(this.schemaName)}, table: ${jsonToTsSource(this.tableName)}, policy: ${jsonToTsSource(input)} })`;
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
override importRequirements(): readonly ImportRequirement[] {
|
|
1603
|
-
return [];
|
|
1595
|
+
return `createRlsPolicy(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.policy)})`;
|
|
1604
1596
|
}
|
|
1605
1597
|
}
|
|
1606
1598
|
|
|
@@ -1631,11 +1623,7 @@ export class DropPostgresRlsPolicyCall extends PostgresOpFactoryCallNode {
|
|
|
1631
1623
|
}
|
|
1632
1624
|
|
|
1633
1625
|
renderTypeScript(): string {
|
|
1634
|
-
return `
|
|
1635
|
-
}
|
|
1636
|
-
|
|
1637
|
-
override importRequirements(): readonly ImportRequirement[] {
|
|
1638
|
-
return [];
|
|
1626
|
+
return `dropRlsPolicy(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.policyName)})`;
|
|
1639
1627
|
}
|
|
1640
1628
|
}
|
|
1641
1629
|
|
|
@@ -1664,11 +1652,7 @@ export class EnableRowLevelSecurityCall extends PostgresOpFactoryCallNode {
|
|
|
1664
1652
|
}
|
|
1665
1653
|
|
|
1666
1654
|
renderTypeScript(): string {
|
|
1667
|
-
return `
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
override importRequirements(): readonly ImportRequirement[] {
|
|
1671
|
-
return [];
|
|
1655
|
+
return `enableRowLevelSecurity(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)})`;
|
|
1672
1656
|
}
|
|
1673
1657
|
}
|
|
1674
1658
|
|
|
@@ -1697,11 +1681,7 @@ export class DisableRowLevelSecurityCall extends PostgresOpFactoryCallNode {
|
|
|
1697
1681
|
}
|
|
1698
1682
|
|
|
1699
1683
|
renderTypeScript(): string {
|
|
1700
|
-
return `
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
|
-
override importRequirements(): readonly ImportRequirement[] {
|
|
1704
|
-
return [];
|
|
1684
|
+
return `disableRowLevelSecurity(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)})`;
|
|
1705
1685
|
}
|
|
1706
1686
|
}
|
|
1707
1687
|
|
|
@@ -1744,11 +1724,7 @@ export class RenamePostgresRlsPolicyCall extends PostgresOpFactoryCallNode {
|
|
|
1744
1724
|
}
|
|
1745
1725
|
|
|
1746
1726
|
renderTypeScript(): string {
|
|
1747
|
-
return `
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
override importRequirements(): readonly ImportRequirement[] {
|
|
1751
|
-
return [];
|
|
1727
|
+
return `renameRlsPolicy(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.oldPolicyName)}, ${jsonToTsSource(this.newPolicyName)})`;
|
|
1752
1728
|
}
|
|
1753
1729
|
}
|
|
1754
1730
|
|
|
@@ -35,7 +35,6 @@ import type {
|
|
|
35
35
|
import { resolveValueSetValues } from '@prisma-next/family-sql/control';
|
|
36
36
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
37
37
|
import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
38
|
-
import { issueOutcome } from '@prisma-next/framework-components/control';
|
|
39
38
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
40
39
|
import {
|
|
41
40
|
type SqlStorage,
|
|
@@ -199,7 +198,7 @@ export const notNullBackfillCallStrategy: CallMigrationStrategy = (issues, ctx)
|
|
|
199
198
|
const calls: PostgresOpFactoryCall[] = [];
|
|
200
199
|
|
|
201
200
|
for (const issue of issues) {
|
|
202
|
-
if (
|
|
201
|
+
if (issue.reason !== 'not-found') continue;
|
|
203
202
|
const node = issueNode(issue);
|
|
204
203
|
if (node === undefined || node.nodeKind !== RelationalSchemaNodeKind.column) continue;
|
|
205
204
|
const expected = blindCast<
|
|
@@ -264,7 +263,7 @@ export const typeChangeCallStrategy: CallMigrationStrategy = (issues, ctx) => {
|
|
|
264
263
|
const calls: PostgresOpFactoryCall[] = [];
|
|
265
264
|
|
|
266
265
|
for (const issue of issues) {
|
|
267
|
-
if (
|
|
266
|
+
if (issue.reason !== 'not-equal') continue;
|
|
268
267
|
const pair = columnNodePair(issue);
|
|
269
268
|
if (pair === undefined) continue;
|
|
270
269
|
const { expected, actual } = pair;
|
|
@@ -358,7 +357,7 @@ export const nullableTighteningCallStrategy: CallMigrationStrategy = (issues, ct
|
|
|
358
357
|
const calls: PostgresOpFactoryCall[] = [];
|
|
359
358
|
|
|
360
359
|
for (const issue of issues) {
|
|
361
|
-
if (
|
|
360
|
+
if (issue.reason !== 'not-equal') continue;
|
|
362
361
|
const pair = columnNodePair(issue);
|
|
363
362
|
if (pair === undefined) continue;
|
|
364
363
|
const { expected, actual } = pair;
|
|
@@ -591,7 +590,7 @@ export const notNullAddColumnCallStrategy: CallMigrationStrategy = (issues, ctx)
|
|
|
591
590
|
const mutableStorageTypes = ctx.storageTypes as Record<string, StorageTypeInstance>;
|
|
592
591
|
|
|
593
592
|
for (const issue of issues) {
|
|
594
|
-
if (
|
|
593
|
+
if (issue.reason !== 'not-found') continue;
|
|
595
594
|
const node = issueNode(issue);
|
|
596
595
|
if (node === undefined || node.nodeKind !== RelationalSchemaNodeKind.column) continue;
|
|
597
596
|
const expected = blindCast<
|
|
@@ -21,7 +21,6 @@ import type {
|
|
|
21
21
|
SchemaDiffIssue,
|
|
22
22
|
SchemaOwnership,
|
|
23
23
|
} from '@prisma-next/framework-components/control';
|
|
24
|
-
import { issueOutcome } from '@prisma-next/framework-components/control';
|
|
25
24
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
26
25
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
27
26
|
import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
@@ -212,7 +211,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
212
211
|
options.policy.allowedOperationClasses.includes('destructive');
|
|
213
212
|
const coalesced = coalesceSubtreeIssues(relationalDiffIssues);
|
|
214
213
|
const owned = retainUnownedExtras(coalesced, options.ownership, options.contract);
|
|
215
|
-
const gated = strict ? owned : owned.filter((issue) =>
|
|
214
|
+
const gated = strict ? owned : owned.filter((issue) => issue.reason !== 'not-expected');
|
|
216
215
|
|
|
217
216
|
// Namespace presence (`CREATE SCHEMA`) is a planner-only op-generation
|
|
218
217
|
// concern stitched in here rather than inside the shared diff — verify
|
|
@@ -370,7 +369,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
370
369
|
// 'not-equal' is unreachable for content-addressed policies: the wire name
|
|
371
370
|
// encodes the body hash, so two policies sharing a local key (same name)
|
|
372
371
|
// are always equal and isEqualTo never returns false.
|
|
373
|
-
if (
|
|
372
|
+
if (issue.reason === 'not-found') {
|
|
374
373
|
const expected = issue.expected;
|
|
375
374
|
PostgresPolicySchemaNode.assert(expected);
|
|
376
375
|
// expected.namespaceId is the DDL schema name (resolved during projection);
|
|
@@ -382,7 +381,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
382
381
|
expected.namespaceId,
|
|
383
382
|
),
|
|
384
383
|
});
|
|
385
|
-
} else if (
|
|
384
|
+
} else if (issue.reason === 'not-expected') {
|
|
386
385
|
const actual = issue.actual;
|
|
387
386
|
PostgresPolicySchemaNode.assert(actual);
|
|
388
387
|
extra.push({
|
|
@@ -506,7 +505,7 @@ function retainUnownedExtras(
|
|
|
506
505
|
): readonly SchemaDiffIssue<SqlSchemaDiffNode>[] {
|
|
507
506
|
if (ownership === undefined) return issues;
|
|
508
507
|
return issues.filter((issue) => {
|
|
509
|
-
if (
|
|
508
|
+
if (issue.reason !== 'not-expected') return true;
|
|
510
509
|
const node = issueNode(issue);
|
|
511
510
|
if (node === undefined) return true;
|
|
512
511
|
const coordinate = postgresNodeStorageCoordinate(node);
|
|
@@ -8,7 +8,6 @@ import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
|
8
8
|
import type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
|
|
9
9
|
import { errorPostgresMigrationStackMissing } from '../errors';
|
|
10
10
|
import { PostgresContractView } from '../postgres-contract-view';
|
|
11
|
-
import { PostgresRlsPolicy, type PostgresRlsPolicyInput } from '../postgres-rls-policy';
|
|
12
11
|
import {
|
|
13
12
|
AddCheckConstraintCall,
|
|
14
13
|
AddColumnCall,
|
|
@@ -20,10 +19,8 @@ import {
|
|
|
20
19
|
type AlterColumnTypeOptions,
|
|
21
20
|
CreateIndexCall,
|
|
22
21
|
CreateNativeEnumTypeCall,
|
|
23
|
-
CreatePostgresRlsPolicyCall,
|
|
24
22
|
CreateSchemaCall,
|
|
25
23
|
CreateTableCall,
|
|
26
|
-
DisableRowLevelSecurityCall,
|
|
27
24
|
DropCheckConstraintCall,
|
|
28
25
|
DropColumnCall,
|
|
29
26
|
DropConstraintCall,
|
|
@@ -31,10 +28,7 @@ import {
|
|
|
31
28
|
DropIndexCall,
|
|
32
29
|
DropNativeEnumTypeCall,
|
|
33
30
|
DropNotNullCall,
|
|
34
|
-
DropPostgresRlsPolicyCall,
|
|
35
31
|
DropTableCall,
|
|
36
|
-
EnableRowLevelSecurityCall,
|
|
37
|
-
RenamePostgresRlsPolicyCall,
|
|
38
32
|
SetDefaultCall,
|
|
39
33
|
SetNotNullCall,
|
|
40
34
|
} from './op-factory-call';
|
|
@@ -426,58 +420,4 @@ export abstract class PostgresMigration<
|
|
|
426
420
|
}): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
|
|
427
421
|
return installExtension(options, this.controlAdapterFor('installExtension'));
|
|
428
422
|
}
|
|
429
|
-
|
|
430
|
-
protected enableRowLevelSecurity(options: {
|
|
431
|
-
readonly schema: string;
|
|
432
|
-
readonly table: string;
|
|
433
|
-
}): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
|
|
434
|
-
return new EnableRowLevelSecurityCall(options.schema, options.table).toOp(
|
|
435
|
-
this.controlAdapterFor('enableRowLevelSecurity'),
|
|
436
|
-
);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
protected disableRowLevelSecurity(options: {
|
|
440
|
-
readonly schema: string;
|
|
441
|
-
readonly table: string;
|
|
442
|
-
}): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
|
|
443
|
-
return new DisableRowLevelSecurityCall(options.schema, options.table).toOp(
|
|
444
|
-
this.controlAdapterFor('disableRowLevelSecurity'),
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
protected createRlsPolicy(options: {
|
|
449
|
-
readonly schema: string;
|
|
450
|
-
readonly table: string;
|
|
451
|
-
readonly policy: PostgresRlsPolicyInput;
|
|
452
|
-
}): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
|
|
453
|
-
return new CreatePostgresRlsPolicyCall(
|
|
454
|
-
options.schema,
|
|
455
|
-
options.table,
|
|
456
|
-
new PostgresRlsPolicy(options.policy),
|
|
457
|
-
).toOp(this.controlAdapterFor('createRlsPolicy'));
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
protected dropRlsPolicy(options: {
|
|
461
|
-
readonly schema: string;
|
|
462
|
-
readonly table: string;
|
|
463
|
-
readonly policy: string;
|
|
464
|
-
}): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
|
|
465
|
-
return new DropPostgresRlsPolicyCall(options.schema, options.table, options.policy).toOp(
|
|
466
|
-
this.controlAdapterFor('dropRlsPolicy'),
|
|
467
|
-
);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
protected renameRlsPolicy(options: {
|
|
471
|
-
readonly schema: string;
|
|
472
|
-
readonly table: string;
|
|
473
|
-
readonly from: string;
|
|
474
|
-
readonly to: string;
|
|
475
|
-
}): Promise<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> {
|
|
476
|
-
return new RenamePostgresRlsPolicyCall(
|
|
477
|
-
options.schema,
|
|
478
|
-
options.table,
|
|
479
|
-
options.from,
|
|
480
|
-
options.to,
|
|
481
|
-
).toOp(this.controlAdapterFor('renameRlsPolicy'));
|
|
482
|
-
}
|
|
483
423
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { DiffableNode
|
|
1
|
+
import type { DiffableNode } from '@prisma-next/framework-components/control';
|
|
2
2
|
import { freezeNode } from '@prisma-next/framework-components/ir';
|
|
3
|
-
import { assertNode,
|
|
3
|
+
import { assertNode, SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
4
4
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
5
5
|
import type { RlsPolicyOperation } from '../postgres-rls-policy';
|
|
6
6
|
import { PostgresSchemaNodeKind } from './schema-node-kinds';
|
|
@@ -23,13 +23,6 @@ export interface PostgresPolicySchemaNodeInput {
|
|
|
23
23
|
readonly withCheck?: string;
|
|
24
24
|
/** `true` = `AS PERMISSIVE`, `false` = `AS RESTRICTIVE`. */
|
|
25
25
|
readonly permissive: boolean;
|
|
26
|
-
/**
|
|
27
|
-
* This policy's table node, plus one entry per role it grants to — each
|
|
28
|
-
* as the root-anchored chain the differ pairs siblings with. Stamped by
|
|
29
|
-
* the derivation, which holds the parent (database/namespace) context.
|
|
30
|
-
* Never compared by `isEqualTo`.
|
|
31
|
-
*/
|
|
32
|
-
readonly dependsOn?: readonly SchemaNodeRef[];
|
|
33
26
|
}
|
|
34
27
|
|
|
35
28
|
/**
|
|
@@ -55,8 +48,6 @@ export class PostgresPolicySchemaNode extends SqlSchemaIRNode implements Diffabl
|
|
|
55
48
|
declare readonly using?: string;
|
|
56
49
|
declare readonly withCheck?: string;
|
|
57
50
|
readonly permissive: boolean;
|
|
58
|
-
/** See {@link PostgresPolicySchemaNodeInput.dependsOn}. Non-enumerable so it stays out of JSON and structural equality, matching `SqlColumnIR.codecRef`. */
|
|
59
|
-
declare readonly dependsOn?: readonly SchemaNodeRef[];
|
|
60
51
|
|
|
61
52
|
constructor(input: PostgresPolicySchemaNodeInput) {
|
|
62
53
|
super();
|
|
@@ -69,7 +60,6 @@ export class PostgresPolicySchemaNode extends SqlSchemaIRNode implements Diffabl
|
|
|
69
60
|
if (input.using !== undefined) this.using = input.using;
|
|
70
61
|
if (input.withCheck !== undefined) this.withCheck = input.withCheck;
|
|
71
62
|
this.permissive = input.permissive;
|
|
72
|
-
defineNonEnumerable(this, 'dependsOn', input.dependsOn);
|
|
73
63
|
freezeNode(this);
|
|
74
64
|
}
|
|
75
65
|
|
|
@@ -10,11 +10,9 @@ export {
|
|
|
10
10
|
CreateExtensionCall,
|
|
11
11
|
CreateIndexCall,
|
|
12
12
|
CreateNativeEnumTypeCall,
|
|
13
|
-
CreatePostgresRlsPolicyCall,
|
|
14
13
|
CreateSchemaCall,
|
|
15
14
|
CreateTableCall,
|
|
16
15
|
DataTransformCall,
|
|
17
|
-
DisableRowLevelSecurityCall,
|
|
18
16
|
DropCheckConstraintCall,
|
|
19
17
|
DropColumnCall,
|
|
20
18
|
DropConstraintCall,
|
|
@@ -22,11 +20,8 @@ export {
|
|
|
22
20
|
DropIndexCall,
|
|
23
21
|
DropNativeEnumTypeCall,
|
|
24
22
|
DropNotNullCall,
|
|
25
|
-
DropPostgresRlsPolicyCall,
|
|
26
23
|
DropTableCall,
|
|
27
|
-
EnableRowLevelSecurityCall,
|
|
28
24
|
RawSqlCall,
|
|
29
|
-
RenamePostgresRlsPolicyCall,
|
|
30
25
|
SetDefaultCall,
|
|
31
26
|
SetNotNullCall,
|
|
32
27
|
} from '../core/migrations/op-factory-call';
|
package/src/exports/types.ts
CHANGED
|
@@ -40,5 +40,4 @@ export {
|
|
|
40
40
|
PostgresTableSchemaNode,
|
|
41
41
|
type PostgresTableSchemaNodeInput,
|
|
42
42
|
} from '../core/schema-ir/postgres-table-schema-node';
|
|
43
|
-
export { PostgresSchemaNodeKind } from '../core/schema-ir/schema-node-kinds';
|
|
44
43
|
export type { PostgresColumnDefault } from '../core/types';
|