@prisma-next/target-postgres 0.14.0-dev.49 → 0.14.0-dev.50
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-DUFgy9jO.mjs +1103 -0
- package/dist/control-policy-DUFgy9jO.mjs.map +1 -0
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +19 -40
- package/dist/control.mjs.map +1 -1
- package/dist/default-normalizer.mjs +247 -1
- package/dist/default-normalizer.mjs.map +1 -0
- package/dist/diff-database-schema-BmSmWcaY.mjs +313 -0
- package/dist/diff-database-schema-BmSmWcaY.mjs.map +1 -0
- package/dist/diff-database-schema.d.mts +46 -0
- package/dist/diff-database-schema.d.mts.map +1 -0
- package/dist/diff-database-schema.mjs +2 -0
- package/dist/issue-planner.d.mts +34 -10
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +2 -2
- package/dist/migration.d.mts +2 -2
- package/dist/migration.mjs +2 -2
- package/dist/native-type-normalizer.mjs +37 -1
- package/dist/native-type-normalizer.mjs.map +1 -0
- package/dist/{op-factory-call-BuoGT5UI.mjs → op-factory-call-BKRnMgrB.mjs} +2 -2
- package/dist/op-factory-call-BKRnMgrB.mjs.map +1 -0
- package/dist/{op-factory-call-Caqus-Qg.d.mts → op-factory-call-Dt-Jx5JS.d.mts} +2 -2
- package/dist/{op-factory-call-Caqus-Qg.d.mts.map → op-factory-call-Dt-Jx5JS.d.mts.map} +1 -1
- package/dist/op-factory-call.d.mts +2 -2
- package/dist/op-factory-call.mjs +2 -2
- package/dist/planner-BMBRPzsv.mjs +367 -0
- package/dist/planner-BMBRPzsv.mjs.map +1 -0
- package/dist/planner-ddl-builders-B8Nn6nHN.mjs.map +1 -1
- package/dist/planner-ddl-builders.d.mts +2 -2
- package/dist/planner-ddl-builders.d.mts.map +1 -1
- package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -1
- package/dist/planner-identity-values.d.mts +7 -1
- package/dist/planner-identity-values.d.mts.map +1 -1
- package/dist/planner-identity-values.mjs +2 -2
- package/dist/{planner-produced-postgres-migration-CtJi4sgS.d.mts → planner-produced-postgres-migration-C0a7I1-e.d.mts} +2 -2
- package/dist/{planner-produced-postgres-migration-CtJi4sgS.d.mts.map → planner-produced-postgres-migration-C0a7I1-e.d.mts.map} +1 -1
- package/dist/{planner-produced-postgres-migration-C2_H6Vvl.mjs → planner-produced-postgres-migration-Dp6IO_gj.mjs} +2 -2
- package/dist/{planner-produced-postgres-migration-C2_H6Vvl.mjs.map → planner-produced-postgres-migration-Dp6IO_gj.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-sql-checks-Cze3vMfe.mjs.map +1 -1
- package/dist/planner-sql-checks.d.mts +1 -1
- package/dist/planner-sql-checks.d.mts.map +1 -1
- package/dist/planner.d.mts +27 -67
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +3 -2
- package/dist/{postgres-database-schema-node-os8ogEap.d.mts → postgres-database-schema-node-C9bTuMrd.d.mts} +14 -7
- package/dist/postgres-database-schema-node-C9bTuMrd.d.mts.map +1 -0
- package/dist/{postgres-migration-D0QIVE-p.mjs → postgres-migration-D0jwzYDT.mjs} +2 -2
- package/dist/{postgres-migration-D0QIVE-p.mjs.map → postgres-migration-D0jwzYDT.mjs.map} +1 -1
- package/dist/{postgres-migration-CfyKDT7b.d.mts → postgres-migration-DFaxuRyI.d.mts} +2 -2
- package/dist/{postgres-migration-CfyKDT7b.d.mts.map → postgres-migration-DFaxuRyI.d.mts.map} +1 -1
- package/dist/{postgres-table-schema-node-Clei_xel.mjs → postgres-table-schema-node-BgaSrxYN.mjs} +30 -29
- package/dist/postgres-table-schema-node-BgaSrxYN.mjs.map +1 -0
- package/dist/schema-node-kinds-ClScchhi.mjs +76 -0
- package/dist/schema-node-kinds-ClScchhi.mjs.map +1 -0
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +1 -1
- package/package.json +21 -20
- package/src/core/migrations/column-ddl-rendering.ts +117 -0
- package/src/core/migrations/contract-to-postgres-database-schema-node.ts +25 -1
- package/src/core/migrations/control-policy.ts +68 -48
- package/src/core/migrations/diff-database-schema.ts +242 -153
- package/src/core/migrations/issue-planner.ts +621 -667
- package/src/core/migrations/operations/constraints.ts +1 -1
- package/src/core/migrations/planner-ddl-builders.ts +5 -2
- package/src/core/migrations/planner-identity-values.ts +1 -1
- package/src/core/migrations/planner-sql-checks.ts +1 -1
- package/src/core/migrations/planner-strategies.ts +248 -208
- package/src/core/migrations/planner.ts +180 -74
- package/src/core/migrations/runner.ts +1 -4
- package/src/core/migrations/verify-postgres-namespaces.ts +26 -15
- package/src/core/postgres-schema-verifier.ts +10 -7
- package/src/core/psl-infer/infer-psl-contract.ts +5 -10
- package/src/core/schema-ir/postgres-database-schema-node.ts +3 -6
- package/src/core/schema-ir/postgres-namespace-schema-node.ts +8 -9
- package/src/core/schema-ir/postgres-policy-schema-node.ts +3 -6
- package/src/core/schema-ir/postgres-role-schema-node.ts +3 -6
- package/src/core/schema-ir/postgres-table-schema-node.ts +20 -9
- package/src/core/schema-ir/schema-node-kinds.ts +80 -2
- package/src/exports/control.ts +10 -43
- package/src/exports/diff-database-schema.ts +7 -0
- package/src/exports/issue-planner.ts +1 -1
- package/src/exports/op-factory-call.ts +1 -0
- package/src/exports/planner-identity-values.ts +4 -1
- package/src/exports/planner.ts +0 -1
- package/dist/default-normalizer-Dug8Fez9.mjs +0 -248
- package/dist/default-normalizer-Dug8Fez9.mjs.map +0 -1
- package/dist/issue-planner-Cbh-xTEr.mjs +0 -849
- package/dist/issue-planner-Cbh-xTEr.mjs.map +0 -1
- package/dist/native-type-normalizer-Bc9XJzWC.mjs +0 -38
- package/dist/native-type-normalizer-Bc9XJzWC.mjs.map +0 -1
- package/dist/op-factory-call-BuoGT5UI.mjs.map +0 -1
- package/dist/planner-Bq0Z2sVO.mjs +0 -641
- package/dist/planner-Bq0Z2sVO.mjs.map +0 -1
- package/dist/postgres-database-schema-node-os8ogEap.d.mts.map +0 -1
- package/dist/postgres-table-schema-node-Clei_xel.mjs.map +0 -1
|
@@ -19,24 +19,32 @@ import type {
|
|
|
19
19
|
MigrationPlanWithAuthoringSurface,
|
|
20
20
|
MigrationScaffoldContext,
|
|
21
21
|
SchemaDiffIssue,
|
|
22
|
-
|
|
22
|
+
SchemaOwnership,
|
|
23
23
|
} from '@prisma-next/framework-components/control';
|
|
24
24
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
25
|
+
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
25
26
|
import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
26
27
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
27
28
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
28
29
|
import { PostgresRlsPolicy } from '../postgres-rls-policy';
|
|
29
30
|
import { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
|
|
30
31
|
import { PostgresPolicySchemaNode } from '../schema-ir/postgres-policy-schema-node';
|
|
31
|
-
import type
|
|
32
|
+
import { PostgresSchemaNodeKind, type SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';
|
|
32
33
|
import {
|
|
33
34
|
formatPostgresControlPolicySubjectLabel,
|
|
35
|
+
resolveNamespaceIdForDdlSchema,
|
|
34
36
|
resolvePostgresCallControlPolicySubject,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
resolvePostgresNodeIssueControlPolicySubject,
|
|
38
|
+
resolvePostgresNodeIssueCreationFactoryName,
|
|
37
39
|
} from './control-policy';
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
+
import { buildPostgresPlanDiff } from './diff-database-schema';
|
|
41
|
+
import {
|
|
42
|
+
coalesceSubtreeIssues,
|
|
43
|
+
issueNode,
|
|
44
|
+
issueSchemaName,
|
|
45
|
+
issueTableName,
|
|
46
|
+
planIssues,
|
|
47
|
+
} from './issue-planner';
|
|
40
48
|
import type { PostgresOpFactoryCall } from './op-factory-call';
|
|
41
49
|
import {
|
|
42
50
|
CreatePostgresRlsPolicyCall,
|
|
@@ -82,18 +90,20 @@ export type PostgresPlanResult =
|
|
|
82
90
|
/**
|
|
83
91
|
* Postgres migration planner — a thin wrapper over `planIssues`.
|
|
84
92
|
*
|
|
85
|
-
* `plan()`
|
|
86
|
-
* `
|
|
87
|
-
* `
|
|
88
|
-
* type-change, nullable-tightening, codec-hook
|
|
89
|
-
* component-declared dependency installs, and
|
|
90
|
-
* empty-table-guarded NOT-NULL add-column. The same
|
|
91
|
-
* `migration plan`, `db update`, and `db init`;
|
|
92
|
-
* `policy.allowedOperationClasses` (the
|
|
93
|
-
* when `'data'` is excluded). The issue
|
|
94
|
-
* policy gates and emits a single
|
|
95
|
-
* the runtime-ops view (via
|
|
96
|
-
* authoring surface.
|
|
93
|
+
* `plan()` diffs the target contract against the live schema via the one
|
|
94
|
+
* differ (`buildPostgresPlanDiff`, producing node-typed `SchemaDiffIssue[]`)
|
|
95
|
+
* and delegates to `planIssues` with the unified `postgresPlannerStrategies`
|
|
96
|
+
* list: NOT-NULL backfill, type-change, nullable-tightening, codec-hook
|
|
97
|
+
* storage types, component-declared dependency installs, and
|
|
98
|
+
* shared-temp-default / empty-table-guarded NOT-NULL add-column. The same
|
|
99
|
+
* strategy list runs for `migration plan`, `db update`, and `db init`;
|
|
100
|
+
* behavior diverges purely on `policy.allowedOperationClasses` (the
|
|
101
|
+
* data-safe strategies short-circuit when `'data'` is excluded). The issue
|
|
102
|
+
* planner applies operation-class policy gates and emits a single
|
|
103
|
+
* `PostgresOpFactoryCall[]` that drives both the runtime-ops view (via
|
|
104
|
+
* `renderOps`) and the `renderTypeScript()` authoring surface. RLS policy
|
|
105
|
+
* drift (the structural half of the same one-differ tree) is handled
|
|
106
|
+
* separately via `planPostgresSchemaDiff`.
|
|
97
107
|
*/
|
|
98
108
|
export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgres'> {
|
|
99
109
|
readonly #lowerer: ExecuteRequestLowerer | undefined;
|
|
@@ -129,6 +139,11 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
129
139
|
* the marker row by the right space.
|
|
130
140
|
*/
|
|
131
141
|
readonly spaceId: string;
|
|
142
|
+
/**
|
|
143
|
+
* Ownership oracle over the contract-space composition — see
|
|
144
|
+
* {@link SqlMigrationPlannerPlanOptions.ownership}.
|
|
145
|
+
*/
|
|
146
|
+
readonly ownership?: SchemaOwnership;
|
|
132
147
|
}): PostgresPlanResult {
|
|
133
148
|
return this.planSql(options as SqlMigrationPlannerPlanOptions);
|
|
134
149
|
}
|
|
@@ -158,25 +173,60 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
158
173
|
return policyResult;
|
|
159
174
|
}
|
|
160
175
|
|
|
161
|
-
//
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
// applied blindly — any scoping (e.g. multi-space ownership) is the
|
|
167
|
-
// orchestration's, never worked out here.
|
|
176
|
+
// The one combined tree diff drives the whole plan: relational findings
|
|
177
|
+
// become structural DDL via `planIssues`, policy findings become RLS ops
|
|
178
|
+
// via `planPostgresSchemaDiff`. Verify runs its own full-tree node diff
|
|
179
|
+
// (`diffSchema`) over the same schema and rejects on a
|
|
180
|
+
// surviving failure.
|
|
168
181
|
PostgresDatabaseSchemaNode.assert(options.schema);
|
|
169
|
-
const
|
|
182
|
+
const { issues: rawIssues } = buildPostgresPlanDiff({
|
|
170
183
|
contract: options.contract,
|
|
171
184
|
actualSchema: options.schema,
|
|
172
|
-
strict:
|
|
173
|
-
options.policy.allowedOperationClasses.includes('widening') ||
|
|
174
|
-
options.policy.allowedOperationClasses.includes('destructive'),
|
|
175
|
-
typeMetadataRegistry: new Map(),
|
|
176
185
|
frameworkComponents: options.frameworkComponents,
|
|
177
186
|
});
|
|
178
|
-
const
|
|
179
|
-
const
|
|
187
|
+
const policyDiffIssues = rawIssues.filter((issue) => isPolicyDiffIssue(issue));
|
|
188
|
+
const relationalDiffIssues = rawIssues.filter((issue) => !isPolicyDiffIssue(issue));
|
|
189
|
+
|
|
190
|
+
// The generic differ is total and un-gated: strict-mode extras filtering
|
|
191
|
+
// (dropping `not-expected` findings outside strict mode, mirroring the
|
|
192
|
+
// retired coordinate walk's `if (strict) { ...extra_* } }` guards),
|
|
193
|
+
// subtree coalescing (a missing/extra table also emits an issue for
|
|
194
|
+
// every child under it — redundant once the table-level Create/Drop call
|
|
195
|
+
// already accounts for the whole subtree), and ownership are all post-diff
|
|
196
|
+
// planner steps.
|
|
197
|
+
//
|
|
198
|
+
// Ownership: a live extra is only this plan's to drop when no contract
|
|
199
|
+
// space owns it. The differ ran against THIS space's contract, so a table
|
|
200
|
+
// a sibling space owns surfaces here as `not-expected`; the planner asks
|
|
201
|
+
// the ownership oracle (the passive aggregate) whether any space declares
|
|
202
|
+
// it and, if so, leaves it alone — it is a sibling's table, not an orphan.
|
|
203
|
+
// A table no space owns stays a genuine extra to drop under a destructive
|
|
204
|
+
// policy. Ownership lives in the aggregate; the planner only asks. Absent
|
|
205
|
+
// oracle (single-space, none handed) keeps every extra. Coalescing MUST
|
|
206
|
+
// run before this so a sibling-owned table's child issues have already
|
|
207
|
+
// collapsed into the one table-level issue that carries the table name.
|
|
208
|
+
const strict =
|
|
209
|
+
options.policy.allowedOperationClasses.includes('widening') ||
|
|
210
|
+
options.policy.allowedOperationClasses.includes('destructive');
|
|
211
|
+
const coalesced = coalesceSubtreeIssues(relationalDiffIssues);
|
|
212
|
+
const owned = retainUnownedExtras(coalesced, options.ownership, options.contract);
|
|
213
|
+
const gated = strict ? owned : owned.filter((issue) => issue.reason !== 'not-expected');
|
|
214
|
+
|
|
215
|
+
// Namespace presence (`CREATE SCHEMA`) is a planner-only op-generation
|
|
216
|
+
// concern stitched in here rather than inside the shared diff — verify
|
|
217
|
+
// never needs it (a missing schema already surfaces as a `not-found`
|
|
218
|
+
// table in the relational findings). These synthesized issues are added
|
|
219
|
+
// AFTER coalescing/scoping (never coalesced against the table diff —
|
|
220
|
+
// their path is an ancestor of every table path under that schema, so
|
|
221
|
+
// running them through the same coalesce would swallow the table-level
|
|
222
|
+
// `not-found` issues that drive `CREATE TABLE`) and are NOT subject to
|
|
223
|
+
// sibling-space scoping, matching the retired coordinate walk exactly.
|
|
224
|
+
const namespaceIssues = verifyPostgresNamespacePresence({
|
|
225
|
+
contract: options.contract,
|
|
226
|
+
schema: options.schema,
|
|
227
|
+
});
|
|
228
|
+
const schemaIssues = [...namespaceIssues, ...gated];
|
|
229
|
+
|
|
180
230
|
const codecHooks = extractCodecControlHooks(options.frameworkComponents);
|
|
181
231
|
const storageTypes = options.contract.storage.types ?? {};
|
|
182
232
|
// The strategy layer reads the live schema by bare table name for existence
|
|
@@ -197,8 +247,8 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
197
247
|
issues: schemaIssues,
|
|
198
248
|
contract: options.contract,
|
|
199
249
|
resolveControlPolicySubject: (issue) =>
|
|
200
|
-
|
|
201
|
-
resolveCreationFactoryName:
|
|
250
|
+
resolvePostgresNodeIssueControlPolicySubject(issue, options.contract),
|
|
251
|
+
resolveCreationFactoryName: resolvePostgresNodeIssueCreationFactoryName,
|
|
202
252
|
formatSubjectLabel: (factoryName, subject) =>
|
|
203
253
|
formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),
|
|
204
254
|
});
|
|
@@ -210,7 +260,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
210
260
|
// `db update` / `db init`, which means data-safety strategies needing
|
|
211
261
|
// from/to comparisons (unsafe type change, nullable tightening) are
|
|
212
262
|
// inapplicable there — reconciliation falls through to
|
|
213
|
-
// `
|
|
263
|
+
// `mapNodeIssueToCall`'s direct destructive handlers.
|
|
214
264
|
fromContract: options.fromContract,
|
|
215
265
|
schemaName,
|
|
216
266
|
codecHooks,
|
|
@@ -225,7 +275,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
225
275
|
return plannerFailure(result.failure);
|
|
226
276
|
}
|
|
227
277
|
|
|
228
|
-
const schemaDiffCalls = this.planPostgresSchemaDiff(options,
|
|
278
|
+
const schemaDiffCalls = this.planPostgresSchemaDiff(options, policyDiffIssues);
|
|
229
279
|
const schemaDiffPartition = partitionCallsByControlPolicy({
|
|
230
280
|
calls: schemaDiffCalls,
|
|
231
281
|
contract: options.contract,
|
|
@@ -284,10 +334,10 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
284
334
|
}
|
|
285
335
|
|
|
286
336
|
/**
|
|
287
|
-
* Maps the RLS policy presence findings of the
|
|
288
|
-
* `
|
|
289
|
-
*
|
|
290
|
-
*
|
|
337
|
+
* Maps the RLS policy presence findings of the one combined tree diff
|
|
338
|
+
* (`buildPostgresPlanDiff`, already ownership-filtered) into `ENABLE RLS`
|
|
339
|
+
* / `CREATE POLICY` / `DROP POLICY` ops. It does not re-diff — it consumes
|
|
340
|
+
* exactly the policy-node subset of the shared diff's issues.
|
|
291
341
|
*/
|
|
292
342
|
private planPostgresSchemaDiff(
|
|
293
343
|
options: PlannerOptionsWithComponents,
|
|
@@ -298,10 +348,10 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
298
348
|
const seenEnableTables = new Set<string>();
|
|
299
349
|
|
|
300
350
|
for (const issue of filteredDiffIssues) {
|
|
301
|
-
// '
|
|
351
|
+
// 'not-equal' is unreachable for content-addressed policies: the wire name
|
|
302
352
|
// encodes the body hash, so two policies sharing a local key (same name)
|
|
303
353
|
// are always equal and isEqualTo never returns false.
|
|
304
|
-
if (issue.
|
|
354
|
+
if (issue.reason === 'not-found') {
|
|
305
355
|
const expected = issue.expected;
|
|
306
356
|
PostgresPolicySchemaNode.assert(expected);
|
|
307
357
|
// expected.namespaceId is the DDL schema name (resolved during projection);
|
|
@@ -322,7 +372,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
322
372
|
policyNodeToContractPolicy(expected),
|
|
323
373
|
),
|
|
324
374
|
);
|
|
325
|
-
} else if (issue.
|
|
375
|
+
} else if (issue.reason === 'not-expected' && allowsDestructive) {
|
|
326
376
|
const actual = issue.actual;
|
|
327
377
|
PostgresPolicySchemaNode.assert(actual);
|
|
328
378
|
const schemaForTable = resolveDdlSchemaForNamespaceStorage(
|
|
@@ -348,50 +398,106 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
348
398
|
}
|
|
349
399
|
return null;
|
|
350
400
|
}
|
|
401
|
+
}
|
|
351
402
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
* the database root, so it takes the whole tree. Policy drift is handled
|
|
361
|
-
* separately via `planPostgresSchemaDiff` from the same shared diff's
|
|
362
|
-
* `schemaDiffIssues`.
|
|
363
|
-
*/
|
|
364
|
-
private collectSchemaIssues(
|
|
365
|
-
options: PlannerOptionsWithComponents,
|
|
366
|
-
relationalIssues: readonly SchemaIssue[],
|
|
367
|
-
): readonly SchemaIssue[] {
|
|
368
|
-
const namespaceIssues = verifyPostgresNamespacePresence({
|
|
369
|
-
contract: options.contract,
|
|
370
|
-
schema: options.schema,
|
|
371
|
-
});
|
|
372
|
-
if (namespaceIssues.length === 0) {
|
|
373
|
-
return relationalIssues;
|
|
374
|
-
}
|
|
375
|
-
return [...namespaceIssues, ...relationalIssues];
|
|
376
|
-
}
|
|
403
|
+
/**
|
|
404
|
+
* A diff issue whose node is an RLS policy — the structural half of the one
|
|
405
|
+
* combined tree diff, routed to `planPostgresSchemaDiff` instead of
|
|
406
|
+
* `planIssues`.
|
|
407
|
+
*/
|
|
408
|
+
function isPolicyDiffIssue(issue: SchemaDiffIssue<SqlSchemaDiffNode>): boolean {
|
|
409
|
+
const node = issue.expected ?? issue.actual;
|
|
410
|
+
return node !== undefined && PostgresPolicySchemaNode.is(node);
|
|
377
411
|
}
|
|
378
412
|
|
|
379
413
|
/**
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
414
|
+
* Drops a `not-expected` issue when it is a whole extra TABLE that some
|
|
415
|
+
* contract space owns, asking the ownership oracle per node.
|
|
416
|
+
*
|
|
417
|
+
* The consultation applies ONLY to table-level extras — a live table this
|
|
418
|
+
* space's contract lacks — identified by asking the issue's own node
|
|
419
|
+
* (`nodeKind === table`), never by counting path segments. `declaresEntity`
|
|
420
|
+
* answers over the whole composition (self included), keyed on the schema-IR
|
|
421
|
+
* entity coordinate so a genuine orphan in one namespace is never conflated
|
|
422
|
+
* with a same-named table a sibling space declares in another, or with a
|
|
423
|
+
* same-named non-table entity (an enum, an RLS policy) a sibling declares in
|
|
424
|
+
* the SAME namespace: a positive answer means another space owns THIS table
|
|
425
|
+
* in THIS namespace (a table this space owned would be in its expected tree,
|
|
426
|
+
* never an extra) — leave it. A negative answer means no space owns it — a
|
|
427
|
+
* genuine orphan to drop. `entityKind` is the literal `'table'` here: this
|
|
428
|
+
* function only ever asks about a node already confirmed to be
|
|
429
|
+
* `PostgresSchemaNodeKind.table` (checked just above), and the diff tree's
|
|
430
|
+
* `nodeKind` vocabulary (`'postgres-table'`) is distinct from the storage
|
|
431
|
+
* `entries` vocabulary `elementCoordinates` walks (`'table'`) — the literal
|
|
432
|
+
* is that storage-entries spelling, not the node kind.
|
|
433
|
+
*
|
|
434
|
+
* The issue path carries the *resolved DDL schema* (e.g. `public`), but a
|
|
435
|
+
* contract space's own declared namespace id can be the unbound sentinel
|
|
436
|
+
* (`__unbound__`) that resolves to that schema — the two spellings would
|
|
437
|
+
* never string-match. `resolveNamespaceIdForDdlSchema` recovers the raw
|
|
438
|
+
* namespace id THIS space's own contract would use for that DDL schema, so
|
|
439
|
+
* a table this space's own unbound namespace declares (and any sibling
|
|
440
|
+
* whose own unbound namespace resolves the same way) is compared on the
|
|
441
|
+
* same coordinate the aggregate's `elementCoordinates` walk yields.
|
|
442
|
+
*
|
|
443
|
+
* A DEEPER extra (an extra column/constraint on a table this space DOES own —
|
|
444
|
+
* only the child drifted, so the table is in the expected tree) is this
|
|
445
|
+
* space's own drift and is always kept for dropping; asking the oracle there
|
|
446
|
+
* would wrongly suppress it, because the owned table answers `true`. Shallower
|
|
447
|
+
* issues (namespace/root) are never ownership-scoped here. No oracle ⇒ every
|
|
448
|
+
* extra is kept (single-space plan).
|
|
449
|
+
*/
|
|
450
|
+
function retainUnownedExtras(
|
|
451
|
+
issues: readonly SchemaDiffIssue<SqlSchemaDiffNode>[],
|
|
452
|
+
ownership: SchemaOwnership | undefined,
|
|
453
|
+
contract: Contract<SqlStorage>,
|
|
454
|
+
): readonly SchemaDiffIssue<SqlSchemaDiffNode>[] {
|
|
455
|
+
if (ownership === undefined) return issues;
|
|
456
|
+
return issues.filter((issue) => {
|
|
457
|
+
if (issue.reason !== 'not-expected') return true;
|
|
458
|
+
const node = issueNode(issue);
|
|
459
|
+
if (node === undefined || node.nodeKind !== PostgresSchemaNodeKind.table) return true;
|
|
460
|
+
const ddlSchemaName = issueSchemaName(issue);
|
|
461
|
+
const tableName = issueTableName(issue);
|
|
462
|
+
if (ddlSchemaName === undefined || tableName === undefined) return true;
|
|
463
|
+
const namespaceId = resolveNamespaceIdForDdlSchema(contract, ddlSchemaName);
|
|
464
|
+
return !ownership.declaresEntity({ namespaceId, entityKind: 'table', entityName: tableName });
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Returns the one namespace node the relational strategy layer probes for
|
|
470
|
+
* live-table existence and reads codec-hook context off — the namespace
|
|
471
|
+
* matching the planner's resolved schema name, or the first namespace when
|
|
472
|
+
* none matches. `undefined` when the tree has no namespaces, so the strategy
|
|
473
|
+
* context uses its empty-schema default.
|
|
384
474
|
*
|
|
385
475
|
* The relational strategies key tables by bare name, so they can only probe one
|
|
386
476
|
* namespace at a time; probing across every namespace at once is future work.
|
|
477
|
+
*
|
|
478
|
+
* Returns the real `PostgresNamespaceSchemaNode` reference rather than a
|
|
479
|
+
* projection: `storageTypePlanCallStrategy` hands this same value to codec
|
|
480
|
+
* `planTypeOperations` hooks as `schema`, and hooks read the Postgres-specific
|
|
481
|
+
* `nativeEnumTypeNames` field off it (via `PostgresNamespaceSchemaNode.is`) to
|
|
482
|
+
* decide whether a native enum type already exists — a projection that only
|
|
483
|
+
* copies `tables` would silently drop that signal. `StrategyContext.schema`'s
|
|
484
|
+
* declared type (`SqlSchemaIR`, shared with SQLite's flat shape) doesn't
|
|
485
|
+
* capture this, so the return is `blindCast` the same way `namespaceSchemaNodes`
|
|
486
|
+
* in the family's relational walk already treats a namespace node as a
|
|
487
|
+
* structurally-`SqlSchemaIR`-shaped value.
|
|
387
488
|
*/
|
|
388
489
|
function relationalNamespaceNode(
|
|
389
490
|
schema: PostgresDatabaseSchemaNode,
|
|
390
491
|
schemaName: string,
|
|
391
492
|
): SqlSchemaIR | undefined {
|
|
392
493
|
const namespaceNodes = Object.values(schema.namespaces);
|
|
393
|
-
const
|
|
394
|
-
|
|
494
|
+
const namespaceNode =
|
|
495
|
+
namespaceNodes.find((node) => node.schemaName === schemaName) ?? namespaceNodes[0];
|
|
496
|
+
if (namespaceNode === undefined) return undefined;
|
|
497
|
+
return blindCast<
|
|
498
|
+
SqlSchemaIR,
|
|
499
|
+
'PostgresNamespaceSchemaNode carries tables (+ nativeEnumTypeNames, read by codec hooks via PostgresNamespaceSchemaNode.is) structurally compatible with the SqlSchemaIR shape the strategy layer declares'
|
|
500
|
+
>(namespaceNode);
|
|
395
501
|
}
|
|
396
502
|
|
|
397
503
|
/**
|
|
@@ -140,10 +140,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
140
140
|
return runnerFailure('SCHEMA_VERIFY_FAILED', schemaVerifyResult.summary, {
|
|
141
141
|
why: 'The resulting database schema does not satisfy the destination contract.',
|
|
142
142
|
meta: {
|
|
143
|
-
issues:
|
|
144
|
-
...schemaVerifyResult.schema.issues,
|
|
145
|
-
...schemaVerifyResult.schema.schemaDiffIssues,
|
|
146
|
-
],
|
|
143
|
+
issues: schemaVerifyResult.schema.issues,
|
|
147
144
|
},
|
|
148
145
|
});
|
|
149
146
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
3
3
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
4
4
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
5
5
|
import type { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
6
6
|
import { DEFAULT_NAMESPACE_ID } from '../namespace-ids';
|
|
7
7
|
import { isPostgresSchema } from '../postgres-schema';
|
|
8
8
|
import { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
|
|
9
|
+
import { PostgresNamespaceSchemaNode } from '../schema-ir/postgres-namespace-schema-node';
|
|
10
|
+
import type { SqlSchemaDiffNode } from '../schema-ir/schema-node-kinds';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Resolves the live-database schema name for a given namespace
|
|
@@ -48,12 +50,13 @@ function existingSchemasFromSchema(schema: SqlSchemaIRNode): readonly string[] {
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/**
|
|
51
|
-
* Emits a `
|
|
52
|
-
* namespace whose live container does not yet
|
|
53
|
-
*
|
|
54
|
-
* multi-schema plan emits `CREATE SCHEMA`
|
|
55
|
-
* a planner-only concern (verify already
|
|
56
|
-
*
|
|
53
|
+
* Emits a `postgres-namespace` `not-found` diff issue for every
|
|
54
|
+
* contract-declared Postgres namespace whose live container does not yet
|
|
55
|
+
* exist. The planner prepends these (node-typed, synthesized) to the
|
|
56
|
+
* relational diff issues so a multi-schema plan emits `CREATE SCHEMA`
|
|
57
|
+
* before the tables that need it — a planner-only concern (verify already
|
|
58
|
+
* rejects via the `not-found` table issues a missing schema already
|
|
59
|
+
* produces), so this is not part of the shared diff.
|
|
57
60
|
*
|
|
58
61
|
* A namespace's live container is the schema returned by its
|
|
59
62
|
* polymorphic `ddlSchemaName(storage)` method — named schemas resolve
|
|
@@ -64,29 +67,37 @@ function existingSchemasFromSchema(schema: SqlSchemaIRNode): readonly string[] {
|
|
|
64
67
|
* introspected list. `public` is suppressed implicitly because the
|
|
65
68
|
* introspection (or its sensible default) always carries it.
|
|
66
69
|
*
|
|
67
|
-
* Each emitted issue
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
70
|
+
* Each emitted issue's path is `['database', ddlName]` — an ancestor of
|
|
71
|
+
* every table path under that schema, so it must never be run through
|
|
72
|
+
* `coalesceSubtreeIssues` alongside the table diff (it would swallow the
|
|
73
|
+
* table-level `not-found` issues that drive `CREATE TABLE`); the planner
|
|
74
|
+
* adds these AFTER coalescing the relational issues, and they are not
|
|
75
|
+
* subject to sibling-space ownership scoping (mirrors the retired
|
|
76
|
+
* coordinate walk, which prepended namespace issues after that filter).
|
|
71
77
|
*/
|
|
72
78
|
export function verifyPostgresNamespacePresence(input: {
|
|
73
79
|
readonly contract: Contract<SqlStorage>;
|
|
74
80
|
readonly schema: SqlSchemaIRNode;
|
|
75
|
-
}): readonly
|
|
81
|
+
}): readonly SchemaDiffIssue<SqlSchemaDiffNode>[] {
|
|
76
82
|
const { contract, schema } = input;
|
|
77
83
|
const existing = new Set(existingSchemasFromSchema(schema));
|
|
78
|
-
const issues:
|
|
84
|
+
const issues: SchemaDiffIssue<SqlSchemaDiffNode>[] = [];
|
|
79
85
|
const namespaceIds = Object.keys(contract.storage.namespaces).sort();
|
|
80
86
|
for (const namespaceId of namespaceIds) {
|
|
81
87
|
if (namespaceId === UNBOUND_NAMESPACE_ID) continue;
|
|
82
88
|
const ddlName = resolveDdlSchemaName(contract.storage, namespaceId);
|
|
83
89
|
if (ddlName === UNBOUND_NAMESPACE_ID) continue;
|
|
84
90
|
if (existing.has(ddlName)) continue;
|
|
91
|
+
const namespace = new PostgresNamespaceSchemaNode({
|
|
92
|
+
schemaName: ddlName,
|
|
93
|
+
tables: {},
|
|
94
|
+
nativeEnumTypeNames: [],
|
|
95
|
+
});
|
|
85
96
|
issues.push({
|
|
86
|
-
|
|
97
|
+
path: ['database', ddlName],
|
|
87
98
|
reason: 'not-found',
|
|
88
|
-
namespaceId,
|
|
89
99
|
message: `Schema "${ddlName}" is missing from database`,
|
|
100
|
+
expected: namespace,
|
|
90
101
|
});
|
|
91
102
|
}
|
|
92
103
|
return issues;
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
2
|
import { SqlSchemaVerifierBase } from '@prisma-next/family-sql/ir';
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
SchemaDiffIssue,
|
|
5
|
+
SchemaVerifyOptions,
|
|
6
|
+
} from '@prisma-next/framework-components/control';
|
|
4
7
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
5
8
|
import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* Postgres target `SchemaVerifier` concretion. Plugs into the
|
|
9
12
|
* SQL-shared verification surface; production verification today still
|
|
10
|
-
* routes through the
|
|
11
|
-
* carries options (codec hooks,
|
|
12
|
-
* that the framework-level
|
|
13
|
-
* surface.
|
|
13
|
+
* routes through the family verify verdict (`verifySqlSchemaByDiff` over
|
|
14
|
+
* `diffPostgresSchema`), which carries options (codec hooks,
|
|
15
|
+
* normalizers, framework components) that the framework-level
|
|
16
|
+
* `SchemaVerifyOptions` shape does not yet surface.
|
|
14
17
|
*
|
|
15
18
|
* The hooks return the empty list pending the call-site migration that
|
|
16
19
|
* routes the existing verifier behaviour through the SPI — at that
|
|
@@ -25,13 +28,13 @@ export class PostgresSchemaVerifier extends SqlSchemaVerifierBase<
|
|
|
25
28
|
> {
|
|
26
29
|
protected verifyCommonSqlSchema(
|
|
27
30
|
_options: SchemaVerifyOptions<Contract<SqlStorage>, SqlSchemaIR>,
|
|
28
|
-
): readonly
|
|
31
|
+
): readonly SchemaDiffIssue[] {
|
|
29
32
|
return [];
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
protected verifyTargetExtensions(
|
|
33
36
|
_options: SchemaVerifyOptions<Contract<SqlStorage>, SqlSchemaIR>,
|
|
34
|
-
): readonly
|
|
37
|
+
): readonly SchemaDiffIssue[] {
|
|
35
38
|
return [];
|
|
36
39
|
}
|
|
37
40
|
}
|
|
@@ -36,12 +36,8 @@ import {
|
|
|
36
36
|
UNSPECIFIED_PSL_NAMESPACE_ID,
|
|
37
37
|
} from '@prisma-next/framework-components/psl-ast';
|
|
38
38
|
import type { SqlModelStorage } from '@prisma-next/sql-contract/types';
|
|
39
|
-
import type {
|
|
40
|
-
|
|
41
|
-
SqlForeignKeyIR,
|
|
42
|
-
SqlSchemaIR,
|
|
43
|
-
SqlTableIR,
|
|
44
|
-
} from '@prisma-next/sql-schema-ir/types';
|
|
39
|
+
import type { SqlColumnIR, SqlForeignKeyIR } from '@prisma-next/sql-schema-ir/types';
|
|
40
|
+
import { SqlSchemaIR, SqlTableIR } from '@prisma-next/sql-schema-ir/types';
|
|
45
41
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
46
42
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
47
43
|
import type { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
|
|
@@ -255,7 +251,7 @@ function resolveForeignKeys(
|
|
|
255
251
|
resultTables[tableName] =
|
|
256
252
|
keptForeignKeys.length === table.foreignKeys.length
|
|
257
253
|
? table
|
|
258
|
-
: { ...table, foreignKeys: keptForeignKeys };
|
|
254
|
+
: new SqlTableIR({ ...table, foreignKeys: keptForeignKeys });
|
|
259
255
|
}
|
|
260
256
|
|
|
261
257
|
return { tables: resultTables, extraRelationsByTable, crossSpaceFieldNamesByTable };
|
|
@@ -335,16 +331,15 @@ export function inferPostgresPslContract(
|
|
|
335
331
|
'output is a later slice).',
|
|
336
332
|
);
|
|
337
333
|
}
|
|
338
|
-
tables[tableName] = table;
|
|
334
|
+
tables[tableName] = new SqlTableIR(table);
|
|
339
335
|
}
|
|
340
336
|
}
|
|
341
|
-
|
|
342
337
|
const {
|
|
343
338
|
tables: resolvedTables,
|
|
344
339
|
extraRelationsByTable,
|
|
345
340
|
crossSpaceFieldNamesByTable,
|
|
346
341
|
} = resolveForeignKeys(tables, owners);
|
|
347
|
-
const schemaIR
|
|
342
|
+
const schemaIR = new SqlSchemaIR({ tables: resolvedTables });
|
|
348
343
|
|
|
349
344
|
const options: PslPrinterOptions = {
|
|
350
345
|
typeMap: createPostgresTypeMap(new Set()),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DiffableNode } from '@prisma-next/framework-components/control';
|
|
2
2
|
import { freezeNode } from '@prisma-next/framework-components/ir';
|
|
3
|
-
import { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
3
|
+
import { assertNode, SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
4
4
|
import type { PostgresNamespaceSchemaNode } from './postgres-namespace-schema-node';
|
|
5
5
|
import type { PostgresRoleSchemaNode } from './postgres-role-schema-node';
|
|
6
6
|
import { PostgresSchemaNodeKind } from './schema-node-kinds';
|
|
@@ -23,6 +23,7 @@ export interface PostgresDatabaseSchemaNodeInput {
|
|
|
23
23
|
*/
|
|
24
24
|
export class PostgresDatabaseSchemaNode extends SqlSchemaIRNode implements DiffableNode {
|
|
25
25
|
override readonly nodeKind = PostgresSchemaNodeKind.database;
|
|
26
|
+
|
|
26
27
|
readonly namespaces: Readonly<Record<string, PostgresNamespaceSchemaNode>>;
|
|
27
28
|
readonly roles: readonly PostgresRoleSchemaNode[];
|
|
28
29
|
readonly existingSchemas: readonly string[];
|
|
@@ -54,10 +55,6 @@ export class PostgresDatabaseSchemaNode extends SqlSchemaIRNode implements Diffa
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
static assert(node: SqlSchemaIRNode): asserts node is PostgresDatabaseSchemaNode {
|
|
57
|
-
|
|
58
|
-
throw new Error(
|
|
59
|
-
`Expected a PostgresDatabaseSchemaNode but got nodeKind=${node.nodeKind ?? 'undefined'}`,
|
|
60
|
-
);
|
|
61
|
-
}
|
|
58
|
+
assertNode(node, 'PostgresDatabaseSchemaNode', PostgresDatabaseSchemaNode.is);
|
|
62
59
|
}
|
|
63
60
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DiffableNode } from '@prisma-next/framework-components/control';
|
|
2
2
|
import { freezeNode } from '@prisma-next/framework-components/ir';
|
|
3
|
-
import { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
3
|
+
import { assertNode, SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
4
4
|
import type { PostgresTableSchemaNode } from './postgres-table-schema-node';
|
|
5
5
|
import { PostgresSchemaNodeKind } from './schema-node-kinds';
|
|
6
6
|
|
|
@@ -12,9 +12,11 @@ export interface PostgresNamespaceSchemaNodeInput {
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* One-per-Postgres-schema diff-tree node. Groups the tables belonging to a
|
|
15
|
-
* single namespace
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* single namespace. Per-schema consumers (the relational planner,
|
|
16
|
+
* toSchemaView) read this node's `tables` field structurally via
|
|
17
|
+
* `blindCast`/`SqlSchemaIRNode` — not through a static `SqlSchemaIR`
|
|
18
|
+
* assignment — because `nodeKind` now carries this node's own literal
|
|
19
|
+
* (`postgres-namespace`), distinct from `SqlSchemaIR`'s own (`sql-schema`).
|
|
18
20
|
*
|
|
19
21
|
* `id` is the schema name. `isEqualTo` is identity — two namespace nodes are
|
|
20
22
|
* equal iff their ids (schema names) match. `children()` returns the table
|
|
@@ -23,6 +25,7 @@ export interface PostgresNamespaceSchemaNodeInput {
|
|
|
23
25
|
*/
|
|
24
26
|
export class PostgresNamespaceSchemaNode extends SqlSchemaIRNode implements DiffableNode {
|
|
25
27
|
override readonly nodeKind = PostgresSchemaNodeKind.namespace;
|
|
28
|
+
|
|
26
29
|
readonly schemaName: string;
|
|
27
30
|
readonly tables: Readonly<Record<string, PostgresTableSchemaNode>>;
|
|
28
31
|
readonly nativeEnumTypeNames: readonly string[];
|
|
@@ -52,10 +55,6 @@ export class PostgresNamespaceSchemaNode extends SqlSchemaIRNode implements Diff
|
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
static assert(node: SqlSchemaIRNode): asserts node is PostgresNamespaceSchemaNode {
|
|
55
|
-
|
|
56
|
-
throw new Error(
|
|
57
|
-
`Expected a PostgresNamespaceSchemaNode but got nodeKind=${node.nodeKind ?? 'undefined'}`,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
58
|
+
assertNode(node, 'PostgresNamespaceSchemaNode', PostgresNamespaceSchemaNode.is);
|
|
60
59
|
}
|
|
61
60
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DiffableNode } from '@prisma-next/framework-components/control';
|
|
2
2
|
import { freezeNode } from '@prisma-next/framework-components/ir';
|
|
3
|
-
import { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
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';
|
|
@@ -38,6 +38,7 @@ export interface PostgresPolicySchemaNodeInput {
|
|
|
38
38
|
*/
|
|
39
39
|
export class PostgresPolicySchemaNode extends SqlSchemaIRNode implements DiffableNode {
|
|
40
40
|
override readonly nodeKind = PostgresSchemaNodeKind.policy;
|
|
41
|
+
|
|
41
42
|
readonly name: string;
|
|
42
43
|
readonly prefix: string;
|
|
43
44
|
readonly tableName: string;
|
|
@@ -84,10 +85,6 @@ export class PostgresPolicySchemaNode extends SqlSchemaIRNode implements Diffabl
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
static assert(node: SqlSchemaIRNode | undefined): asserts node is PostgresPolicySchemaNode {
|
|
87
|
-
|
|
88
|
-
throw new Error(
|
|
89
|
-
`Expected a PostgresPolicySchemaNode but got nodeKind=${node?.nodeKind ?? 'undefined'}`,
|
|
90
|
-
);
|
|
91
|
-
}
|
|
88
|
+
assertNode(node, 'PostgresPolicySchemaNode', PostgresPolicySchemaNode.is);
|
|
92
89
|
}
|
|
93
90
|
}
|