@prisma-next/target-postgres 0.14.0-dev.21 → 0.14.0-dev.23
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-free.mjs +2 -2
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +8 -7
- package/dist/control.mjs.map +1 -1
- package/dist/{ddl-BJPdPsT3.mjs → ddl-CGf6UABz.mjs} +2 -2
- package/dist/{ddl-BJPdPsT3.mjs.map → ddl-CGf6UABz.mjs.map} +1 -1
- package/dist/{descriptor-meta-CKpjK2Nv.mjs → descriptor-meta-Dvvpu_jU.mjs} +3 -3
- package/dist/{descriptor-meta-CKpjK2Nv.mjs.map → descriptor-meta-Dvvpu_jU.mjs.map} +1 -1
- package/dist/{descriptor-meta-runtime-DiVla56r.mjs → descriptor-meta-runtime-D5zHFKUz.mjs} +2 -2
- package/dist/descriptor-meta-runtime-D5zHFKUz.mjs.map +1 -0
- package/dist/{issue-planner-YwXUKGZ1.mjs → issue-planner-D5H1VuVP.mjs} +4 -4
- package/dist/{issue-planner-YwXUKGZ1.mjs.map → issue-planner-D5H1VuVP.mjs.map} +1 -1
- package/dist/issue-planner.d.mts +2 -2
- 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-DcY4BHNh.mjs → op-factory-call-DIdBDwmO.mjs} +3 -3
- package/dist/op-factory-call-DIdBDwmO.mjs.map +1 -0
- package/dist/{op-factory-call-CQ4P40QC.d.mts → op-factory-call-DPJR7tJc.d.mts} +3 -3
- package/dist/{op-factory-call-CQ4P40QC.d.mts.map → op-factory-call-DPJR7tJc.d.mts.map} +1 -1
- package/dist/op-factory-call.d.mts +1 -1
- package/dist/op-factory-call.mjs +1 -1
- package/dist/pack.d.mts +2 -3
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/{planner-_ZHpIQ1-.mjs → planner-BnNEtGYM.mjs} +116 -76
- package/dist/planner-BnNEtGYM.mjs.map +1 -0
- package/dist/{planner-produced-postgres-migration-CNTSCMl7.d.mts → planner-produced-postgres-migration-BO-frvvN.d.mts} +2 -2
- package/dist/{planner-produced-postgres-migration-CNTSCMl7.d.mts.map → planner-produced-postgres-migration-BO-frvvN.d.mts.map} +1 -1
- package/dist/{planner-produced-postgres-migration-Dv5ZAvHt.mjs → planner-produced-postgres-migration-DzvdQ-7K.mjs} +2 -2
- package/dist/{planner-produced-postgres-migration-Dv5ZAvHt.mjs.map → planner-produced-postgres-migration-DzvdQ-7K.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-C7nLjabn.mjs → planner-sql-checks-CyjaoKhm.mjs} +2 -2
- package/dist/{planner-sql-checks-C7nLjabn.mjs.map → planner-sql-checks-CyjaoKhm.mjs.map} +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/planner.d.mts +30 -35
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +2 -2
- package/dist/{postgres-contract-serializer-DJDGaS0q.mjs → postgres-contract-serializer-tGMiJcl4.mjs} +3 -3
- package/dist/{postgres-contract-serializer-DJDGaS0q.mjs.map → postgres-contract-serializer-tGMiJcl4.mjs.map} +1 -1
- package/dist/{postgres-migration-Bj0olfl3.mjs → postgres-migration-C8JZyTSJ.mjs} +2 -2
- package/dist/{postgres-migration-Bj0olfl3.mjs.map → postgres-migration-C8JZyTSJ.mjs.map} +1 -1
- package/dist/{postgres-migration-DJNJHcdP.d.mts → postgres-migration-Cs7zMOe1.d.mts} +3 -3
- package/dist/{postgres-migration-DJNJHcdP.d.mts.map → postgres-migration-Cs7zMOe1.d.mts.map} +1 -1
- package/dist/{postgres-rls-policy-D_z1osEq.d.mts → postgres-rls-policy-12wAEQhs.d.mts} +4 -4
- package/dist/postgres-rls-policy-12wAEQhs.d.mts.map +1 -0
- package/dist/{postgres-schema-Bn4tsMuo.d.mts → postgres-schema-DJUEkWg-.d.mts} +38 -5
- package/dist/postgres-schema-DJUEkWg-.d.mts.map +1 -0
- package/dist/{postgres-schema-DfuJq-q_.mjs → postgres-schema-DLcc3W2-.mjs} +37 -40
- package/dist/postgres-schema-DLcc3W2-.mjs.map +1 -0
- package/dist/postgres-schema-ir-BJl_a3J7.d.mts +102 -0
- package/dist/postgres-schema-ir-BJl_a3J7.d.mts.map +1 -0
- package/dist/postgres-schema-ir-I_FiUndw.mjs +133 -0
- package/dist/postgres-schema-ir-I_FiUndw.mjs.map +1 -0
- package/dist/{postgres-schema-ir-annotations-CWHQ-H9Y.mjs → postgres-schema-ir-annotations-BbDSiwx2.mjs} +4 -4
- package/dist/postgres-schema-ir-annotations-BbDSiwx2.mjs.map +1 -0
- package/dist/runtime.mjs +2 -2
- package/dist/schema-ir-annotations.d.mts +1 -1
- package/dist/schema-ir-annotations.d.mts.map +1 -1
- package/dist/schema-ir-annotations.mjs +1 -1
- package/dist/types.d.mts +4 -5
- package/dist/types.mjs +3 -3
- package/package.json +19 -19
- package/src/core/authoring.ts +2 -2
- package/src/core/entity-kinds.ts +2 -2
- package/src/core/migrations/contract-to-postgres-schema-ir.ts +91 -0
- package/src/core/migrations/diff-postgres-schema.ts +55 -0
- package/src/core/migrations/op-factory-call.ts +1 -1
- package/src/core/migrations/operations/rls.ts +1 -1
- package/src/core/migrations/planner.ts +44 -59
- package/src/core/migrations/verify-postgres-namespaces.ts +1 -1
- package/src/core/postgres-schema.ts +6 -2
- package/src/core/{postgres-rls-policy.ts → schema-ir/postgres-rls-policy.ts} +8 -10
- package/src/core/{postgres-role.ts → schema-ir/postgres-role.ts} +8 -9
- package/src/core/{postgres-schema-ir-annotations.ts → schema-ir/postgres-schema-ir-annotations.ts} +1 -1
- package/src/core/{postgres-schema-ir.ts → schema-ir/postgres-schema-ir.ts} +53 -16
- package/src/core/schema-ir/postgres-table-ir.ts +96 -0
- package/src/exports/control.ts +11 -12
- package/src/exports/planner.ts +5 -1
- package/src/exports/schema-ir-annotations.ts +1 -1
- package/src/exports/types.ts +15 -7
- package/dist/descriptor-meta-runtime-DiVla56r.mjs.map +0 -1
- package/dist/op-factory-call-DcY4BHNh.mjs.map +0 -1
- package/dist/planner-_ZHpIQ1-.mjs.map +0 -1
- package/dist/postgres-rls-policy-D_z1osEq.d.mts.map +0 -1
- package/dist/postgres-role-_CCuyPCQ.d.mts +0 -33
- package/dist/postgres-role-_CCuyPCQ.d.mts.map +0 -1
- package/dist/postgres-schema-Bn4tsMuo.d.mts.map +0 -1
- package/dist/postgres-schema-DfuJq-q_.mjs.map +0 -1
- package/dist/postgres-schema-ir-BF0X8jit.mjs +0 -66
- package/dist/postgres-schema-ir-BF0X8jit.mjs.map +0 -1
- package/dist/postgres-schema-ir-BQ3RpZMz.d.mts +0 -60
- package/dist/postgres-schema-ir-BQ3RpZMz.d.mts.map +0 -1
- package/dist/postgres-schema-ir-annotations-CWHQ-H9Y.mjs.map +0 -1
- package/src/core/migrations/verify-postgres-rls-policies.ts +0 -62
|
@@ -25,16 +25,18 @@ import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
|
25
25
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
26
26
|
import { parsePostgresDefault } from '../default-normalizer';
|
|
27
27
|
import { normalizeSchemaNativeType } from '../native-type-normalizer';
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import { resolveDdlSchemaForNamespaceStorage } from '../postgres-schema-ir-annotations';
|
|
28
|
+
import type { PostgresContract } from '../postgres-schema';
|
|
29
|
+
import { assertPostgresRlsPolicy } from '../schema-ir/postgres-rls-policy';
|
|
30
|
+
import { assertPostgresSchemaIR, ensurePostgresSchemaIR } from '../schema-ir/postgres-schema-ir';
|
|
31
|
+
import { resolveDdlSchemaForNamespaceStorage } from '../schema-ir/postgres-schema-ir-annotations';
|
|
32
|
+
import { contractToPostgresSchemaIR } from './contract-to-postgres-schema-ir';
|
|
32
33
|
import {
|
|
33
34
|
formatPostgresControlPolicySubjectLabel,
|
|
34
35
|
resolvePostgresCallControlPolicySubject,
|
|
35
36
|
resolvePostgresIssueControlPolicySubject,
|
|
36
37
|
resolvePostgresIssueCreationFactoryName,
|
|
37
38
|
} from './control-policy';
|
|
39
|
+
import { diffPostgresSchema, filterIssuesByOwnership } from './diff-postgres-schema';
|
|
38
40
|
import { planIssues } from './issue-planner';
|
|
39
41
|
import type { PostgresOpFactoryCall } from './op-factory-call';
|
|
40
42
|
import {
|
|
@@ -45,7 +47,6 @@ import {
|
|
|
45
47
|
import { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';
|
|
46
48
|
import { postgresPlannerStrategies } from './planner-strategies';
|
|
47
49
|
import { verifyPostgresNamespacePresence } from './verify-postgres-namespaces';
|
|
48
|
-
import { diffPostgresRlsPolicies } from './verify-postgres-rls-policies';
|
|
49
50
|
|
|
50
51
|
type PlannerFrameworkComponents = SqlMigrationPlannerPlanOptions extends {
|
|
51
52
|
readonly frameworkComponents: infer T;
|
|
@@ -204,36 +205,9 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
204
205
|
return plannerFailure(result.failure);
|
|
205
206
|
}
|
|
206
207
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
//
|
|
211
|
-
// Fail loud when the contract declares RLS policies but the schema is
|
|
212
|
-
// contract-derived (migration plan path). Without a live-introspected
|
|
213
|
-
// PostgresSchemaIR there is no baseline to reconcile against, so
|
|
214
|
-
// silently emitting no RLS DDL would be wrong. The user must run
|
|
215
|
-
// `db update` / `db init` against a live database to emit RLS.
|
|
216
|
-
if (!isPostgresSchemaIR(options.schema)) {
|
|
217
|
-
const policyNames: string[] = [];
|
|
218
|
-
for (const ns of Object.values(options.contract.storage.namespaces)) {
|
|
219
|
-
if (isPostgresSchema(ns)) {
|
|
220
|
-
for (const [policyName, policy] of Object.entries(ns.policy)) {
|
|
221
|
-
policyNames.push(`${policy.tableName}.${policyName}`);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
if (policyNames.length > 0) {
|
|
226
|
-
return plannerFailure([
|
|
227
|
-
{
|
|
228
|
-
kind: 'unsupportedOperation',
|
|
229
|
-
summary: `migration plan does not yet emit RLS policies (the offline contract→schema derivation cannot carry them). Author RLS via 'db update' / 'db init' against a live database. Tracked for a follow-up slice (extension migration participation seam). Affected policies: ${policyNames.join(', ')}`,
|
|
230
|
-
},
|
|
231
|
-
]);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
const rlsCalls = this.planRlsDiff(options);
|
|
235
|
-
const rlsPartition = partitionCallsByControlPolicy({
|
|
236
|
-
calls: rlsCalls,
|
|
208
|
+
const schemaDiffCalls = this.planPostgresSchemaDiff(options);
|
|
209
|
+
const schemaDiffPartition = partitionCallsByControlPolicy({
|
|
210
|
+
calls: schemaDiffCalls,
|
|
237
211
|
contract: options.contract,
|
|
238
212
|
resolveControlPolicySubject: (call) =>
|
|
239
213
|
resolvePostgresCallControlPolicySubject(call, options.contract),
|
|
@@ -267,10 +241,10 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
267
241
|
formatSubjectLabel: (factoryName, subject) =>
|
|
268
242
|
formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),
|
|
269
243
|
});
|
|
270
|
-
const calls = [...result.value.calls, ...
|
|
244
|
+
const calls = [...result.value.calls, ...schemaDiffPartition.kept, ...fieldEventPartition.kept];
|
|
271
245
|
const warnings: SqlPlannerConflict[] = [
|
|
272
246
|
...issuePartition.warnings,
|
|
273
|
-
...
|
|
247
|
+
...schemaDiffPartition.warnings,
|
|
274
248
|
...fieldEventPartition.warnings,
|
|
275
249
|
];
|
|
276
250
|
|
|
@@ -289,35 +263,41 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
289
263
|
});
|
|
290
264
|
}
|
|
291
265
|
|
|
292
|
-
private
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
266
|
+
private planPostgresSchemaDiff(
|
|
267
|
+
options: PlannerOptionsWithComponents,
|
|
268
|
+
): readonly PostgresOpFactoryCall[] {
|
|
269
|
+
assertPostgresSchemaIR(options.schema);
|
|
270
|
+
const expected = contractToPostgresSchemaIR(
|
|
271
|
+
blindCast<PostgresContract, 'planPostgresSchemaDiff is only called with a postgres contract'>(
|
|
272
|
+
options.contract,
|
|
273
|
+
),
|
|
274
|
+
{ annotationNamespace: 'pg' },
|
|
275
|
+
);
|
|
276
|
+
const actual = ensurePostgresSchemaIR(options.schema);
|
|
277
|
+
const rawIssues = diffPostgresSchema(expected, actual);
|
|
278
|
+
const ownedSchemaNames = new Set([
|
|
279
|
+
...expected.rlsPolicies.map((p) => p.namespaceId),
|
|
280
|
+
...expected.existingSchemas,
|
|
281
|
+
]);
|
|
282
|
+
const filteredDiffIssues = filterIssuesByOwnership(rawIssues, ownedSchemaNames);
|
|
303
283
|
|
|
304
284
|
const allowsDestructive = options.policy.allowedOperationClasses.includes('destructive');
|
|
305
285
|
const calls: PostgresOpFactoryCall[] = [];
|
|
306
286
|
const seenEnableTables = new Set<string>();
|
|
307
287
|
|
|
308
|
-
for (const issue of
|
|
309
|
-
const { namespaceId, entityName: policyName } = issue.coordinate;
|
|
310
|
-
const schemaForTable = resolveDdlSchemaForNamespaceStorage(
|
|
311
|
-
options.contract.storage,
|
|
312
|
-
namespaceId,
|
|
313
|
-
options.schema,
|
|
314
|
-
);
|
|
315
|
-
|
|
288
|
+
for (const issue of filteredDiffIssues) {
|
|
316
289
|
// 'mismatch' is unreachable for content-addressed policies: the wire name
|
|
317
|
-
// encodes the body hash, so two policies sharing a
|
|
290
|
+
// encodes the body hash, so two policies sharing a local key (same name)
|
|
318
291
|
// are always equal and isEqualTo never returns false.
|
|
319
292
|
if (issue.outcome === 'missing') {
|
|
320
293
|
assertPostgresRlsPolicy(issue.expected);
|
|
294
|
+
// issue.expected.namespaceId is the DDL schema name (resolved during projection);
|
|
295
|
+
// this re-resolution is a no-op as long as PostgresSchema.ddlSchemaName() returns this.id.
|
|
296
|
+
const schemaForTable = resolveDdlSchemaForNamespaceStorage(
|
|
297
|
+
options.contract.storage,
|
|
298
|
+
issue.expected.namespaceId,
|
|
299
|
+
options.schema,
|
|
300
|
+
);
|
|
321
301
|
const tableKey = `${schemaForTable}.${issue.expected.tableName}`;
|
|
322
302
|
if (!seenEnableTables.has(tableKey)) {
|
|
323
303
|
seenEnableTables.add(tableKey);
|
|
@@ -328,8 +308,13 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
328
308
|
);
|
|
329
309
|
} else if (issue.outcome === 'extra' && allowsDestructive) {
|
|
330
310
|
assertPostgresRlsPolicy(issue.actual);
|
|
311
|
+
const schemaForTable = resolveDdlSchemaForNamespaceStorage(
|
|
312
|
+
options.contract.storage,
|
|
313
|
+
issue.actual.namespaceId,
|
|
314
|
+
options.schema,
|
|
315
|
+
);
|
|
331
316
|
calls.push(
|
|
332
|
-
new DropPostgresRlsPolicyCall(schemaForTable, issue.actual.tableName,
|
|
317
|
+
new DropPostgresRlsPolicyCall(schemaForTable, issue.actual.tableName, issue.actual.name),
|
|
333
318
|
);
|
|
334
319
|
}
|
|
335
320
|
}
|
|
@@ -371,7 +356,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
371
356
|
// rather than in the family verifier. Stitch it in here so a single
|
|
372
357
|
// `SchemaIssue[]` flows through `planIssues` and the planner emits
|
|
373
358
|
// CREATE SCHEMA in the dep bucket before any CreateTableCall.
|
|
374
|
-
//
|
|
359
|
+
// Schema drift is handled separately via diffPostgresSchema → planPostgresSchemaDiff.
|
|
375
360
|
const namespaceIssues = verifyPostgresNamespacePresence({
|
|
376
361
|
contract: options.contract,
|
|
377
362
|
schema: options.schema,
|
|
@@ -4,7 +4,7 @@ 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 { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
6
6
|
import { isPostgresSchema } from '../postgres-schema';
|
|
7
|
-
import { isPostgresSchemaIR } from '../postgres-schema-ir';
|
|
7
|
+
import { isPostgresSchemaIR } from '../schema-ir/postgres-schema-ir';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Resolves the live-database schema name for a given namespace
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Contract } from '@prisma-next/contract/types';
|
|
1
2
|
import {
|
|
2
3
|
freezeNode,
|
|
3
4
|
hydrateNamespaceEntities,
|
|
@@ -12,16 +13,19 @@ import {
|
|
|
12
13
|
type StorageTable,
|
|
13
14
|
type StorageValueSet,
|
|
14
15
|
} from '@prisma-next/sql-contract/types';
|
|
16
|
+
|
|
15
17
|
import { type CfExpr, cfExpr } from '@prisma-next/sql-relational-core/contract-free';
|
|
16
18
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
17
19
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
18
20
|
import { PostgresTableSource } from './ast/table-source';
|
|
19
21
|
import { PG_TEXT_CODEC_ID } from './codec-ids';
|
|
20
22
|
import { policyEntityKind, roleEntityKind } from './entity-kinds';
|
|
21
|
-
import type { PostgresRlsPolicy } from './postgres-rls-policy';
|
|
22
|
-
import type { PostgresRole } from './postgres-role';
|
|
23
|
+
import type { PostgresRlsPolicy } from './schema-ir/postgres-rls-policy';
|
|
24
|
+
import type { PostgresRole } from './schema-ir/postgres-role';
|
|
23
25
|
import { escapeLiteral } from './sql-utils';
|
|
24
26
|
|
|
27
|
+
export type PostgresContract = Contract<SqlStorage> & { readonly target: 'postgres' };
|
|
28
|
+
|
|
25
29
|
export type PostgresNamespaceEntries = SqlNamespaceEntries & {
|
|
26
30
|
readonly policy?: Readonly<Record<string, PostgresRlsPolicy>>;
|
|
27
31
|
readonly role?: Readonly<Record<string, PostgresRole>>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { DiffableNode } from '@prisma-next/framework-components/control';
|
|
2
|
-
import type { EntityCoordinate } from '@prisma-next/framework-components/ir';
|
|
3
2
|
import { freezeNode } from '@prisma-next/framework-components/ir';
|
|
4
3
|
import { SqlNode } from '@prisma-next/sql-contract/types';
|
|
5
4
|
|
|
@@ -60,13 +59,12 @@ export class PostgresRlsPolicy extends SqlNode implements DiffableNode {
|
|
|
60
59
|
freezeNode(this);
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
return
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
62
|
+
get id(): string {
|
|
63
|
+
return this.name;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
children(): readonly DiffableNode[] {
|
|
67
|
+
return [];
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
/**
|
|
@@ -80,7 +78,7 @@ export class PostgresRlsPolicy extends SqlNode implements DiffableNode {
|
|
|
80
78
|
isEqualTo(other: DiffableNode): boolean {
|
|
81
79
|
if (!isPostgresRlsPolicy(other)) {
|
|
82
80
|
throw new Error(
|
|
83
|
-
`PostgresRlsPolicy.isEqualTo: expected a PostgresRlsPolicy, got ${other.
|
|
81
|
+
`PostgresRlsPolicy.isEqualTo: expected a PostgresRlsPolicy, got ${other.constructor?.name ?? typeof other}`,
|
|
84
82
|
);
|
|
85
83
|
}
|
|
86
84
|
return this.name === other.name;
|
|
@@ -97,7 +95,7 @@ export function assertPostgresRlsPolicy(
|
|
|
97
95
|
if (!isPostgresRlsPolicy(node)) {
|
|
98
96
|
const kind = node !== undefined && 'kind' in node ? String(node.kind) : typeof node;
|
|
99
97
|
throw new Error(
|
|
100
|
-
`
|
|
98
|
+
`planPostgresSchemaDiff: expected a PostgresRlsPolicy on the policy-diff path but got ${kind}`,
|
|
101
99
|
);
|
|
102
100
|
}
|
|
103
101
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { DiffableNode } from '@prisma-next/framework-components/control';
|
|
2
|
-
import type { EntityCoordinate } from '@prisma-next/framework-components/ir';
|
|
3
2
|
import { freezeNode } from '@prisma-next/framework-components/ir';
|
|
4
3
|
import { SqlNode } from '@prisma-next/sql-contract/types';
|
|
5
4
|
|
|
@@ -33,19 +32,19 @@ export class PostgresRole extends SqlNode implements DiffableNode {
|
|
|
33
32
|
freezeNode(this);
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
/** Roles are cluster-unique; the name alone is sufficient as the id. */
|
|
36
|
+
get id(): string {
|
|
37
|
+
return this.name;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
children(): readonly DiffableNode[] {
|
|
41
|
+
return [];
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
isEqualTo(other: DiffableNode): boolean {
|
|
46
45
|
if (!(other instanceof PostgresRole)) {
|
|
47
46
|
throw new Error(
|
|
48
|
-
`PostgresRole.isEqualTo: expected a PostgresRole, got ${other.
|
|
47
|
+
`PostgresRole.isEqualTo: expected a PostgresRole, got ${other.constructor?.name ?? typeof other}`,
|
|
49
48
|
);
|
|
50
49
|
}
|
|
51
50
|
return this.name === other.name;
|
package/src/core/{postgres-schema-ir-annotations.ts → schema-ir/postgres-schema-ir-annotations.ts}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
2
2
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
3
3
|
import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
4
|
-
import { isPostgresSchema } from '
|
|
4
|
+
import { isPostgresSchema } from '../postgres-schema';
|
|
5
5
|
import { isPostgresSchemaIR } from './postgres-schema-ir';
|
|
6
6
|
|
|
7
7
|
export function resolveDdlSchemaForNamespaceStorage(
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
+
import type { DiffableNode } from '@prisma-next/framework-components/control';
|
|
1
2
|
import { freezeNode } from '@prisma-next/framework-components/ir';
|
|
2
3
|
import {
|
|
3
4
|
type SqlAnnotations,
|
|
4
5
|
type SqlSchemaIR,
|
|
5
6
|
SqlSchemaIRNode,
|
|
6
7
|
type SqlSchemaTarget,
|
|
7
|
-
SqlTableIR,
|
|
8
8
|
type SqlTableIRInput,
|
|
9
9
|
} from '@prisma-next/sql-schema-ir/types';
|
|
10
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
10
11
|
import type { PostgresRlsPolicy } from './postgres-rls-policy';
|
|
11
12
|
import type { PostgresRole } from './postgres-role';
|
|
13
|
+
import { PostgresTableIR } from './postgres-table-ir';
|
|
12
14
|
|
|
13
15
|
export interface PostgresSchemaIRInput {
|
|
14
|
-
readonly tables: Record<
|
|
16
|
+
readonly tables: Record<
|
|
17
|
+
string,
|
|
18
|
+
PostgresTableIR | (SqlTableIRInput & { rlsPolicies?: readonly PostgresRlsPolicy[] })
|
|
19
|
+
>;
|
|
15
20
|
readonly pgSchemaName: string;
|
|
16
21
|
readonly pgVersion: string;
|
|
17
|
-
readonly rlsPolicies: readonly PostgresRlsPolicy[];
|
|
18
22
|
readonly roles: readonly PostgresRole[];
|
|
19
23
|
readonly existingSchemas: readonly string[];
|
|
20
24
|
readonly nativeEnumTypeNames: readonly string[];
|
|
@@ -31,22 +35,18 @@ export interface PostgresSchemaIRInput {
|
|
|
31
35
|
* `SqlSchemaIR` structure and freezes itself at the end of its own
|
|
32
36
|
* constructor.
|
|
33
37
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* reads (`nativeEnumTypeNames`, `existingSchemas`, `schema`) so family-layer
|
|
38
|
-
* PSL inference and namespace verification continue to work without knowing
|
|
39
|
-
* about RLS.
|
|
38
|
+
* `tables` holds `PostgresTableIR` instances which carry their own RLS
|
|
39
|
+
* policies. `children()` returns the tables directly — the table instances
|
|
40
|
+
* ARE the diff-tree nodes.
|
|
40
41
|
*
|
|
41
42
|
* Nothing RLS-specific leaks into the sql-family layer.
|
|
42
43
|
*/
|
|
43
|
-
export class PostgresSchemaIR extends SqlSchemaIRNode {
|
|
44
|
+
export class PostgresSchemaIR extends SqlSchemaIRNode implements DiffableNode {
|
|
44
45
|
readonly nodeTarget: SqlSchemaTarget = 'postgres';
|
|
45
|
-
readonly tables: Readonly<Record<string,
|
|
46
|
+
readonly tables: Readonly<Record<string, PostgresTableIR>>;
|
|
46
47
|
declare readonly annotations?: SqlAnnotations;
|
|
47
48
|
readonly pgSchemaName: string;
|
|
48
49
|
readonly pgVersion: string;
|
|
49
|
-
readonly rlsPolicies: readonly PostgresRlsPolicy[];
|
|
50
50
|
readonly roles: readonly PostgresRole[];
|
|
51
51
|
readonly existingSchemas: readonly string[];
|
|
52
52
|
readonly nativeEnumTypeNames: readonly string[];
|
|
@@ -57,20 +57,18 @@ export class PostgresSchemaIR extends SqlSchemaIRNode {
|
|
|
57
57
|
Object.fromEntries(
|
|
58
58
|
Object.entries(input.tables).map(([key, t]) => [
|
|
59
59
|
key,
|
|
60
|
-
t instanceof
|
|
60
|
+
t instanceof PostgresTableIR ? t : new PostgresTableIR(t),
|
|
61
61
|
]),
|
|
62
62
|
),
|
|
63
63
|
);
|
|
64
64
|
this.pgSchemaName = input.pgSchemaName;
|
|
65
65
|
this.pgVersion = input.pgVersion;
|
|
66
|
-
this.rlsPolicies = Object.freeze([...input.rlsPolicies]);
|
|
67
66
|
this.roles = Object.freeze([...input.roles]);
|
|
68
67
|
this.existingSchemas = Object.freeze([...input.existingSchemas]);
|
|
69
68
|
this.nativeEnumTypeNames = Object.freeze([...input.nativeEnumTypeNames]);
|
|
70
69
|
// Populate the annotations.pg bag with only the subset the family layer
|
|
71
70
|
// reads (nativeEnumTypeNames for PSL inference, existingSchemas for
|
|
72
|
-
// namespace presence checks).
|
|
73
|
-
// — they are consumed directly via typed fields on this class.
|
|
71
|
+
// namespace presence checks).
|
|
74
72
|
this.annotations = {
|
|
75
73
|
pg: {
|
|
76
74
|
schema: input.pgSchemaName,
|
|
@@ -84,6 +82,22 @@ export class PostgresSchemaIR extends SqlSchemaIRNode {
|
|
|
84
82
|
};
|
|
85
83
|
freezeNode(this);
|
|
86
84
|
}
|
|
85
|
+
|
|
86
|
+
get id(): string {
|
|
87
|
+
return this.pgSchemaName;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get rlsPolicies(): readonly PostgresRlsPolicy[] {
|
|
91
|
+
return Object.values(this.tables).flatMap((t) => t.rlsPolicies);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
isEqualTo(_other: DiffableNode): boolean {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
children(): readonly DiffableNode[] {
|
|
99
|
+
return Object.values(this.tables);
|
|
100
|
+
}
|
|
87
101
|
}
|
|
88
102
|
|
|
89
103
|
/**
|
|
@@ -99,3 +113,26 @@ export class PostgresSchemaIR extends SqlSchemaIRNode {
|
|
|
99
113
|
export function isPostgresSchemaIR(schema: SqlSchemaIR): schema is PostgresSchemaIR {
|
|
100
114
|
return schema.nodeTarget === 'postgres';
|
|
101
115
|
}
|
|
116
|
+
|
|
117
|
+
export function assertPostgresSchemaIR(schema: SqlSchemaIR): asserts schema is PostgresSchemaIR {
|
|
118
|
+
if (!isPostgresSchemaIR(schema)) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`planPostgresSchemaDiff: expected a PostgresSchemaIR but got nodeTarget=${String(schema.nodeTarget ?? typeof schema)}`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Returns `schema` as-is when it is a real `PostgresSchemaIR` instance, or
|
|
127
|
+
* reconstructs one when `projectSchemaToSpace` has spread the class into a
|
|
128
|
+
* plain object (losing prototype methods).
|
|
129
|
+
*/
|
|
130
|
+
export function ensurePostgresSchemaIR(schema: PostgresSchemaIR): PostgresSchemaIR {
|
|
131
|
+
if (schema instanceof PostgresSchemaIR) return schema;
|
|
132
|
+
return new PostgresSchemaIR(
|
|
133
|
+
blindCast<
|
|
134
|
+
PostgresSchemaIRInput,
|
|
135
|
+
'spread objects from projectSchemaToSpace preserve all own-enumerable fields'
|
|
136
|
+
>(schema),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { DiffableNode } from '@prisma-next/framework-components/control';
|
|
2
|
+
import { freezeNode } from '@prisma-next/framework-components/ir';
|
|
3
|
+
import {
|
|
4
|
+
PrimaryKey,
|
|
5
|
+
type SqlAnnotations,
|
|
6
|
+
SqlCheckConstraintIR,
|
|
7
|
+
SqlColumnIR,
|
|
8
|
+
SqlForeignKeyIR,
|
|
9
|
+
SqlIndexIR,
|
|
10
|
+
SqlSchemaIRNode,
|
|
11
|
+
type SqlTableIRInput,
|
|
12
|
+
SqlUniqueIR,
|
|
13
|
+
} from '@prisma-next/sql-schema-ir/types';
|
|
14
|
+
import type { PostgresRlsPolicy } from './postgres-rls-policy';
|
|
15
|
+
|
|
16
|
+
export interface PostgresTableIRInput extends SqlTableIRInput {
|
|
17
|
+
readonly rlsPolicies?: readonly PostgresRlsPolicy[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Postgres-specific table IR node. Carries all `SqlTableIR` fields plus
|
|
22
|
+
* `rlsPolicies`, and implements `DiffableNode` so the table instance is
|
|
23
|
+
* directly the diff-tree node — no separate wrapper needed.
|
|
24
|
+
*
|
|
25
|
+
* Extends `SqlSchemaIRNode` directly rather than `SqlTableIR` because
|
|
26
|
+
* `SqlTableIR` calls `freezeNode` in its own constructor, which prevents
|
|
27
|
+
* subclass field initialisation. Same pattern as `PostgresSchemaIR`.
|
|
28
|
+
*
|
|
29
|
+
* `id` is the table name. `children()` returns the policies on this table.
|
|
30
|
+
* `isEqualTo` is always true — table-level attributes are not diffed yet.
|
|
31
|
+
*/
|
|
32
|
+
export class PostgresTableIR extends SqlSchemaIRNode implements DiffableNode {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly columns: Readonly<Record<string, SqlColumnIR>>;
|
|
35
|
+
readonly foreignKeys: ReadonlyArray<SqlForeignKeyIR>;
|
|
36
|
+
readonly uniques: ReadonlyArray<SqlUniqueIR>;
|
|
37
|
+
readonly indexes: ReadonlyArray<SqlIndexIR>;
|
|
38
|
+
declare readonly primaryKey?: PrimaryKey;
|
|
39
|
+
declare readonly annotations?: SqlAnnotations;
|
|
40
|
+
declare readonly checks?: ReadonlyArray<SqlCheckConstraintIR>;
|
|
41
|
+
readonly rlsPolicies: readonly PostgresRlsPolicy[];
|
|
42
|
+
|
|
43
|
+
constructor(input: PostgresTableIRInput) {
|
|
44
|
+
super();
|
|
45
|
+
this.name = input.name;
|
|
46
|
+
this.columns = Object.freeze(
|
|
47
|
+
Object.fromEntries(
|
|
48
|
+
Object.entries(input.columns).map(([key, col]) => [
|
|
49
|
+
key,
|
|
50
|
+
col instanceof SqlColumnIR ? col : new SqlColumnIR(col),
|
|
51
|
+
]),
|
|
52
|
+
),
|
|
53
|
+
);
|
|
54
|
+
this.foreignKeys = Object.freeze(
|
|
55
|
+
input.foreignKeys.map((fk) => (fk instanceof SqlForeignKeyIR ? fk : new SqlForeignKeyIR(fk))),
|
|
56
|
+
);
|
|
57
|
+
this.uniques = Object.freeze(
|
|
58
|
+
input.uniques.map((u) => (u instanceof SqlUniqueIR ? u : new SqlUniqueIR(u))),
|
|
59
|
+
);
|
|
60
|
+
this.indexes = Object.freeze(
|
|
61
|
+
input.indexes.map((i) => (i instanceof SqlIndexIR ? i : new SqlIndexIR(i))),
|
|
62
|
+
);
|
|
63
|
+
if (input.primaryKey !== undefined) {
|
|
64
|
+
this.primaryKey =
|
|
65
|
+
input.primaryKey instanceof PrimaryKey
|
|
66
|
+
? input.primaryKey
|
|
67
|
+
: new PrimaryKey(input.primaryKey);
|
|
68
|
+
}
|
|
69
|
+
if (input.annotations !== undefined) this.annotations = input.annotations;
|
|
70
|
+
if (input.checks !== undefined && input.checks.length > 0) {
|
|
71
|
+
this.checks = Object.freeze(
|
|
72
|
+
input.checks.map((c) =>
|
|
73
|
+
c instanceof SqlCheckConstraintIR ? c : new SqlCheckConstraintIR(c),
|
|
74
|
+
),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
this.rlsPolicies = Object.freeze([...(input.rlsPolicies ?? [])]);
|
|
78
|
+
freezeNode(this);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get id(): string {
|
|
82
|
+
return this.name;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
isEqualTo(_other: DiffableNode): boolean {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
children(): readonly DiffableNode[] {
|
|
90
|
+
return this.rlsPolicies;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function isPostgresTableIR(node: DiffableNode): node is PostgresTableIR {
|
|
95
|
+
return node instanceof PostgresTableIR;
|
|
96
|
+
}
|
package/src/exports/control.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import type { ColumnDefault
|
|
1
|
+
import type { ColumnDefault } from '@prisma-next/contract/types';
|
|
2
2
|
import type { SqlControlTargetDescriptor } from '@prisma-next/family-sql/control';
|
|
3
|
-
import {
|
|
3
|
+
import { extractCodecControlHooks } from '@prisma-next/family-sql/control';
|
|
4
4
|
import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
|
|
5
5
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
6
6
|
import type {
|
|
7
7
|
ControlTargetInstance,
|
|
8
8
|
MigrationRunner,
|
|
9
9
|
} from '@prisma-next/framework-components/control';
|
|
10
|
-
import type {
|
|
10
|
+
import type { StorageColumn } from '@prisma-next/sql-contract/types';
|
|
11
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
11
12
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
12
13
|
import { postgresTargetDescriptorMeta } from '../core/descriptor-meta';
|
|
14
|
+
import { contractToPostgresSchemaIR } from '../core/migrations/contract-to-postgres-schema-ir';
|
|
13
15
|
import { createPostgresMigrationPlanner } from '../core/migrations/planner';
|
|
14
16
|
import { renderDefaultLiteral } from '../core/migrations/planner-ddl-builders';
|
|
15
17
|
import type { PostgresPlanTargetDetails } from '../core/migrations/planner-target-details';
|
|
16
18
|
import { createPostgresMigrationRunner } from '../core/migrations/runner';
|
|
17
19
|
import { PostgresContractSerializer } from '../core/postgres-contract-serializer';
|
|
20
|
+
import type { PostgresContract } from '../core/postgres-schema';
|
|
18
21
|
import { PostgresSchemaVerifier } from '../core/postgres-schema-verifier';
|
|
19
22
|
|
|
20
23
|
function buildNativeTypeExpander(
|
|
@@ -58,15 +61,11 @@ const postgresTargetDescriptor: SqlControlTargetDescriptor<'postgres', PostgresP
|
|
|
58
61
|
},
|
|
59
62
|
contractToSchema(contract, frameworkComponents) {
|
|
60
63
|
const expander = buildNativeTypeExpander(frameworkComponents);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// would have refused to construct a postgres target binding
|
|
67
|
-
// otherwise — so we narrow the generic to
|
|
68
|
-
// `Contract<SqlStorage>` for the lowering call.
|
|
69
|
-
return contractToSchemaIR(contract as unknown as Contract<SqlStorage> | null, {
|
|
64
|
+
const postgresContract = blindCast<
|
|
65
|
+
PostgresContract | null,
|
|
66
|
+
'the family resolver only binds this hook for a Postgres-target contract'
|
|
67
|
+
>(contract);
|
|
68
|
+
return contractToPostgresSchemaIR(postgresContract, {
|
|
70
69
|
annotationNamespace: 'pg',
|
|
71
70
|
...ifDefined('expandNativeType', expander),
|
|
72
71
|
renderDefault: postgresRenderDefault,
|
package/src/exports/planner.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
+
export { contractToPostgresSchemaIR } from '../core/migrations/contract-to-postgres-schema-ir';
|
|
2
|
+
export {
|
|
3
|
+
diffPostgresSchema,
|
|
4
|
+
filterIssuesByOwnership,
|
|
5
|
+
} from '../core/migrations/diff-postgres-schema';
|
|
1
6
|
export { createPostgresMigrationPlanner } from '../core/migrations/planner';
|
|
2
|
-
export { diffPostgresRlsPolicies } from '../core/migrations/verify-postgres-rls-policies';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { resolveDdlSchemaForNamespaceStorage } from '../core/postgres-schema-ir-annotations';
|
|
1
|
+
export { resolveDdlSchemaForNamespaceStorage } from '../core/schema-ir/postgres-schema-ir-annotations';
|
package/src/exports/types.ts
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
|
-
export {
|
|
2
|
-
PostgresRlsPolicy,
|
|
3
|
-
type PostgresRlsPolicyInput,
|
|
4
|
-
type RlsPolicyOperation,
|
|
5
|
-
} from '../core/postgres-rls-policy';
|
|
6
|
-
export { PostgresRole, type PostgresRoleInput } from '../core/postgres-role';
|
|
7
1
|
export {
|
|
8
2
|
isPostgresSchema,
|
|
3
|
+
type PostgresContract,
|
|
9
4
|
PostgresSchema,
|
|
10
5
|
PostgresUnboundSchema,
|
|
11
6
|
postgresCreateNamespace,
|
|
12
7
|
} from '../core/postgres-schema';
|
|
13
8
|
export {
|
|
9
|
+
PostgresRlsPolicy,
|
|
10
|
+
type PostgresRlsPolicyInput,
|
|
11
|
+
type RlsPolicyOperation,
|
|
12
|
+
} from '../core/schema-ir/postgres-rls-policy';
|
|
13
|
+
export { PostgresRole, type PostgresRoleInput } from '../core/schema-ir/postgres-role';
|
|
14
|
+
export {
|
|
15
|
+
assertPostgresSchemaIR,
|
|
16
|
+
ensurePostgresSchemaIR,
|
|
14
17
|
isPostgresSchemaIR,
|
|
15
18
|
PostgresSchemaIR,
|
|
16
19
|
type PostgresSchemaIRInput,
|
|
17
|
-
} from '../core/postgres-schema-ir';
|
|
20
|
+
} from '../core/schema-ir/postgres-schema-ir';
|
|
21
|
+
export {
|
|
22
|
+
isPostgresTableIR,
|
|
23
|
+
PostgresTableIR,
|
|
24
|
+
type PostgresTableIRInput,
|
|
25
|
+
} from '../core/schema-ir/postgres-table-ir';
|
|
18
26
|
export type { PostgresColumnDefault } from '../core/types';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"descriptor-meta-runtime-DiVla56r.mjs","names":[],"sources":["../src/core/authoring.ts","../src/core/descriptor-meta-runtime.ts"],"sourcesContent":["import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';\nimport type {\n AuthoringEntityContext,\n AuthoringEntityTypeNamespace,\n AuthoringFieldNamespace,\n AuthoringPslBlockDescriptorNamespace,\n AuthoringTypeNamespace,\n PslExtensionBlock,\n} from '@prisma-next/framework-components/authoring';\nimport { PostgresRlsPolicy } from './postgres-rls-policy';\nimport { PostgresRole, type PostgresRoleInput } from './postgres-role';\nimport { PostgresRlsPolicySchema, PostgresRoleSchema } from './postgres-validators';\nimport { computeContentHash, normalizePredicate } from './rls/canonicalize';\n\nexport const postgresAuthoringTypes = {} as const satisfies AuthoringTypeNamespace;\n\nexport interface RlsPolicyExtensionBlock extends PslExtensionBlock {\n readonly namespaceId: string;\n}\n\nfunction readRefParam(block: PslExtensionBlock, key: string): string | undefined {\n const param = block.parameters[key];\n return param?.kind === 'ref' ? param.identifier : undefined;\n}\n\nfunction readValueParam(block: PslExtensionBlock, key: string): string | undefined {\n const param = block.parameters[key];\n return param?.kind === 'value' ? param.raw : undefined;\n}\n\nfunction readListRefParams(block: PslExtensionBlock, key: string): string[] {\n const param = block.parameters[key];\n if (param?.kind !== 'list') return [];\n return param.items.flatMap((item) => (item.kind === 'ref' ? [item.identifier] : []));\n}\n\nfunction unwrapQuotedString(raw: string): string {\n if (raw.startsWith('\"') && raw.endsWith('\"') && raw.length >= 2) {\n return raw.slice(1, -1).replace(/\\\\\"/g, '\"');\n }\n return raw;\n}\n\nfunction lowerRlsPolicyFromBlock(\n block: RlsPolicyExtensionBlock,\n _ctx: AuthoringEntityContext,\n): PostgresRlsPolicy {\n const prefix = block.name;\n const targetModelName = readRefParam(block, 'target') ?? '';\n const tableName = targetModelName.charAt(0).toLowerCase() + targetModelName.slice(1);\n const roles = [...readListRefParams(block, 'roles')].sort();\n const using = unwrapQuotedString(readValueParam(block, 'using') ?? '');\n\n const wireHash = computeContentHash({\n using: normalizePredicate(using),\n roles,\n operation: 'select',\n permissive: true,\n });\n const wireName = `${prefix}_${wireHash}`;\n\n return new PostgresRlsPolicy({\n name: wireName,\n prefix,\n tableName,\n namespaceId: block.namespaceId,\n operation: 'select',\n roles,\n using,\n permissive: true,\n });\n}\n\nexport const postgresAuthoringEntityTypes = {\n role: {\n kind: 'entity',\n discriminator: 'role',\n validatorSchema: PostgresRoleSchema,\n output: {\n factory: (input: PostgresRoleInput): PostgresRole => new PostgresRole(input),\n },\n },\n policy: {\n kind: 'entity',\n discriminator: 'policy',\n validatorSchema: PostgresRlsPolicySchema,\n output: {\n factory: lowerRlsPolicyFromBlock,\n },\n },\n} as const satisfies AuthoringEntityTypeNamespace;\n\n/**\n * Field presets contributed by the Postgres target pack.\n *\n * These mirror the PSL scalar-to-codec mapping used by the Postgres adapter\n * (see `createPostgresPslScalarTypeDescriptors`), so that authoring a field\n * via the TS callback surface (e.g. `field.int()`) and via the PSL scalar\n * surface (e.g. `Int`) lowers to byte-identical contracts.\n *\n * The `uuidNative` / `id.uuidv4Native` / `id.uuidv7Native` presets use the\n * native Postgres `uuid` type (codecId `pg/uuid@1`). For cross-target\n * portability use `uuidString` / `id.uuidv4String` / `id.uuidv7String` from\n * the family pack instead.\n */\n/**\n * PSL block descriptor for `policy_select`.\n *\n * The parser learns the block shape from this descriptor; lowering from\n * `PslExtensionBlock` to `PostgresRlsPolicy` is wired in the PSL\n * interpreter (a later dispatch). The `discriminator` matches\n * `PostgresRlsPolicy.kind` so the parsed block node carries the same\n * discriminant as the IR class it will lower to.\n *\n * The `roles` list uses `scope:'cross-space'` because same-namespace\n * role ref resolution requires PSL namespace entries keyed by `refKind`\n * (i.e. `'role'`), which in turn requires the role block discriminator to\n * equal `'role'`. Aligning discriminator with refKind is tracked for\n * slice 4 (cross-space roles). Until then cross-space passes validation\n * unconditionally and the authored role names flow through unchanged.\n */\nexport const postgresAuthoringPslBlockDescriptors = {\n policy_select: {\n kind: 'pslBlock',\n keyword: 'policy_select',\n discriminator: 'policy',\n name: { required: true },\n parameters: {\n target: { kind: 'ref', refKind: 'model', scope: 'same-namespace', required: true },\n roles: {\n kind: 'list',\n of: { kind: 'ref', refKind: 'role', scope: 'cross-space' },\n },\n using: { kind: 'value', codecId: 'pg/text@1', required: true },\n },\n },\n} as const satisfies AuthoringPslBlockDescriptorNamespace;\n\nexport const postgresAuthoringFieldPresets = {\n text: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/text@1',\n nativeType: 'text',\n },\n },\n int: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int4@1',\n nativeType: 'int4',\n },\n },\n bigint: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int8@1',\n nativeType: 'int8',\n },\n },\n float: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/float8@1',\n nativeType: 'float8',\n },\n },\n decimal: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/numeric@1',\n nativeType: 'numeric',\n },\n },\n boolean: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bool@1',\n nativeType: 'bool',\n },\n },\n json: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/jsonb@1',\n nativeType: 'jsonb',\n },\n },\n bytes: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bytea@1',\n nativeType: 'bytea',\n },\n },\n dateTime: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n },\n },\n temporal: /* @__PURE__ */ temporalAuthoringPresets({\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n }),\n uuidNative: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n },\n },\n id: {\n uuidv4Native: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n executionDefaults: {\n onCreate: {\n kind: 'generator',\n id: 'uuidv4',\n },\n },\n id: true,\n },\n },\n uuidv7Native: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n executionDefaults: {\n onCreate: {\n kind: 'generator',\n id: 'uuidv7',\n },\n },\n id: true,\n },\n },\n },\n} as const satisfies AuthoringFieldNamespace;\n","// Runtime-safe slice of the postgres target descriptor metadata.\n//\n// This file exists separately from ./descriptor-meta on purpose: the runtime\n// plane reads only `kind/familyId/targetId/id/version/capabilities` (plus the\n// `__codecTypes` phantom). The `authoring` slot lives on the pack/control\n// descriptor only, because authoring contributions are consumed at\n// contract-construction time by `assembleAuthoringContributions` (control\n// plane) and the PSL interpreter — never at runtime.\n//\n// Keeping the runtime closure free of the `./authoring` import is what lets\n// the bundler tree-shake `@prisma-next/family-sql/control` (and its\n// transitive `verify-sql-schema` chunk) out of the runtime entry. Do not\n// add an `authoring` field here — if you need to, the pack/control meta in\n// `./descriptor-meta` is the right place. See TML-2766 for context.\nimport type { CodecTypes } from '../exports/codec-types';\n\nconst postgresTargetDescriptorMetaRuntimeBase = {\n kind: 'target',\n familyId: 'sql',\n targetId: 'postgres',\n id: 'postgres',\n version: '0.0.1',\n capabilities: {},\n} as const;\n\nexport const postgresTargetDescriptorMetaRuntime: typeof postgresTargetDescriptorMetaRuntimeBase & {\n readonly __codecTypes?: CodecTypes;\n} = postgresTargetDescriptorMetaRuntimeBase;\n"],"mappings":"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"}
|