@prisma-next/target-postgres 0.14.0-dev.44 → 0.14.0-dev.46
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/authoring-DzHOdWTl.mjs +364 -0
- package/dist/authoring-DzHOdWTl.mjs.map +1 -0
- package/dist/{codec-ids-CnXu9Qy3.d.mts → codec-ids-BzrFF-I4.d.mts} +3 -2
- package/dist/codec-ids-BzrFF-I4.d.mts.map +1 -0
- package/dist/{codec-ids-BvytN2P8.mjs → codec-ids-C_-Hj6bL.mjs} +3 -2
- package/dist/codec-ids-C_-Hj6bL.mjs.map +1 -0
- package/dist/codec-ids.d.mts +2 -2
- package/dist/codec-ids.mjs +2 -2
- package/dist/{codec-types-CueCoGD0.d.mts → codec-types-BDVmvKAW.d.mts} +3 -2
- package/dist/codec-types-BDVmvKAW.d.mts.map +1 -0
- package/dist/codec-types.d.mts +1 -1
- package/dist/{codecs-Ca8upop6.d.mts → codecs-Dk2sxGLv.d.mts} +66 -4
- package/dist/codecs-Dk2sxGLv.d.mts.map +1 -0
- package/dist/codecs.d.mts +1 -1
- package/dist/codecs.mjs +83 -1
- package/dist/codecs.mjs.map +1 -1
- package/dist/contract-free.mjs +3 -3
- package/dist/control.d.mts +1 -1
- package/dist/control.mjs +138 -13
- package/dist/control.mjs.map +1 -1
- package/dist/{data-transform-qKy1U5V9.d.mts → data-transform-DPzwBMhW.d.mts} +2 -2
- package/dist/{data-transform-qKy1U5V9.d.mts.map → data-transform-DPzwBMhW.d.mts.map} +1 -1
- package/dist/data-transform.d.mts +1 -1
- package/dist/{ddl-BmLIe1z_.mjs → ddl-ujxH2A7r.mjs} +3 -3
- package/dist/{ddl-BmLIe1z_.mjs.map → ddl-ujxH2A7r.mjs.map} +1 -1
- package/dist/{descriptor-meta-tjatyhtZ.mjs → descriptor-meta-CuGDsrG4.mjs} +5 -4
- package/dist/descriptor-meta-CuGDsrG4.mjs.map +1 -0
- package/dist/{issue-planner-DbFvaAgu.mjs → issue-planner-Cbh-xTEr.mjs} +6 -6
- package/dist/{issue-planner-DbFvaAgu.mjs.map → issue-planner-Cbh-xTEr.mjs.map} +1 -1
- package/dist/issue-planner.d.mts +2 -2
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.d.mts +3 -3
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +2 -2
- package/dist/namespace-ids-xtp_ZY86.mjs +7 -0
- package/dist/namespace-ids-xtp_ZY86.mjs.map +1 -0
- package/dist/{op-factory-call-t65c4jyY.mjs → op-factory-call-BuoGT5UI.mjs} +6 -5
- package/dist/op-factory-call-BuoGT5UI.mjs.map +1 -0
- package/dist/{op-factory-call-CJWUxyUW.d.mts → op-factory-call-Caqus-Qg.d.mts} +2 -2
- package/dist/{op-factory-call-CJWUxyUW.d.mts.map → op-factory-call-Caqus-Qg.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 +43 -3
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/{planner-CG2pLHk-.mjs → planner-CMXuFrQB.mjs} +10 -9
- package/dist/planner-CMXuFrQB.mjs.map +1 -0
- package/dist/planner-ddl-builders.d.mts +1 -1
- package/dist/planner-identity-values.d.mts +1 -1
- package/dist/{planner-produced-postgres-migration-BolD0Mvc.mjs → planner-produced-postgres-migration-CikV-edi.mjs} +2 -2
- package/dist/{planner-produced-postgres-migration-BolD0Mvc.mjs.map → planner-produced-postgres-migration-CikV-edi.mjs.map} +1 -1
- package/dist/{planner-produced-postgres-migration-Cz9--XOT.d.mts → planner-produced-postgres-migration-CtJi4sgS.d.mts} +2 -2
- package/dist/{planner-produced-postgres-migration-Cz9--XOT.d.mts.map → planner-produced-postgres-migration-CtJi4sgS.d.mts.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-DE9c4519.mjs → planner-sql-checks-Cze3vMfe.mjs} +2 -2
- package/dist/{planner-sql-checks-DE9c4519.mjs.map → planner-sql-checks-Cze3vMfe.mjs.map} +1 -1
- package/dist/planner-sql-checks.d.mts +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/planner.d.mts +3 -3
- package/dist/planner.mjs +1 -1
- package/dist/{postgres-contract-view-BegduLr6.mjs → postgres-contract-view-V3rGJCoe.mjs} +23 -14
- package/dist/postgres-contract-view-V3rGJCoe.mjs.map +1 -0
- package/dist/{postgres-migration-BfMmK6tv.mjs → postgres-migration-CZApTUCK.mjs} +3 -3
- package/dist/{postgres-migration-BfMmK6tv.mjs.map → postgres-migration-CZApTUCK.mjs.map} +1 -1
- package/dist/{postgres-migration-D7kNVWVG.d.mts → postgres-migration-CfyKDT7b.d.mts} +4 -4
- package/dist/{postgres-migration-D7kNVWVG.d.mts.map → postgres-migration-CfyKDT7b.d.mts.map} +1 -1
- package/dist/postgres-native-enum-xdiqmBf_.mjs +41 -0
- package/dist/postgres-native-enum-xdiqmBf_.mjs.map +1 -0
- package/dist/{postgres-schema-BLIHBEfX.mjs → postgres-schema-CajYAwny.mjs} +32 -7
- package/dist/postgres-schema-CajYAwny.mjs.map +1 -0
- package/dist/{postgres-schema-BywoeKlt.d.mts → postgres-schema-DqnhQRvR.d.mts} +40 -3
- package/dist/postgres-schema-DqnhQRvR.d.mts.map +1 -0
- package/dist/{postgres-table-schema-node-1nNc8XDT.mjs → postgres-table-schema-node-Clei_xel.mjs} +2 -2
- package/dist/{postgres-table-schema-node-1nNc8XDT.mjs.map → postgres-table-schema-node-Clei_xel.mjs.map} +1 -1
- package/dist/{resolve-ddl-schema-CL1RR1mx.mjs → resolve-ddl-schema-Bv1ZvjX8.mjs} +8 -6
- package/dist/resolve-ddl-schema-Bv1ZvjX8.mjs.map +1 -0
- package/dist/runtime.d.mts +9 -0
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/schema-ir-annotations.d.mts +4 -3
- package/dist/schema-ir-annotations.d.mts.map +1 -1
- package/dist/schema-ir-annotations.mjs +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +2 -2
- package/package.json +20 -20
- package/src/core/authoring.ts +173 -2
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codec-type-map.ts +2 -0
- package/src/core/codecs.ts +106 -0
- package/src/core/descriptor-meta.ts +2 -1
- package/src/core/entity-kinds.ts +15 -1
- package/src/core/migrations/operations/dependencies.ts +2 -1
- package/src/core/migrations/resolve-ddl-schema.ts +6 -4
- package/src/core/migrations/verify-postgres-namespaces.ts +2 -1
- package/src/core/namespace-ids.ts +3 -0
- package/src/core/postgres-contract-serializer.ts +27 -21
- package/src/core/postgres-native-enum.ts +51 -0
- package/src/core/postgres-schema.ts +28 -4
- package/src/core/postgres-validators.ts +7 -0
- package/src/core/psl-infer/infer-psl-contract.ts +246 -7
- package/src/exports/control.ts +2 -2
- package/dist/authoring-BX1WHIdN.mjs +0 -220
- package/dist/authoring-BX1WHIdN.mjs.map +0 -1
- package/dist/codec-ids-BvytN2P8.mjs.map +0 -1
- package/dist/codec-ids-CnXu9Qy3.d.mts.map +0 -1
- package/dist/codec-types-CueCoGD0.d.mts.map +0 -1
- package/dist/codecs-Ca8upop6.d.mts.map +0 -1
- package/dist/descriptor-meta-tjatyhtZ.mjs.map +0 -1
- package/dist/op-factory-call-t65c4jyY.mjs.map +0 -1
- package/dist/planner-CG2pLHk-.mjs.map +0 -1
- package/dist/postgres-contract-view-BegduLr6.mjs.map +0 -1
- package/dist/postgres-schema-BLIHBEfX.mjs.map +0 -1
- package/dist/postgres-schema-BywoeKlt.d.mts.map +0 -1
- package/dist/resolve-ddl-schema-CL1RR1mx.mjs.map +0 -1
- package/src/core/postgres-enum-type-schema.ts +0 -17
|
@@ -19,7 +19,8 @@ import { blindCast } from '@prisma-next/utils/casts';
|
|
|
19
19
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
20
20
|
import { PostgresTableSource } from './ast/table-source';
|
|
21
21
|
import { PG_TEXT_CODEC_ID } from './codec-ids';
|
|
22
|
-
import { policyEntityKind, roleEntityKind } from './entity-kinds';
|
|
22
|
+
import { nativeEnumEntityKind, policyEntityKind, roleEntityKind } from './entity-kinds';
|
|
23
|
+
import type { PostgresNativeEnum } from './postgres-native-enum';
|
|
23
24
|
import type { PostgresRlsPolicy } from './postgres-rls-policy';
|
|
24
25
|
import type { PostgresRole } from './postgres-role';
|
|
25
26
|
import { escapeLiteral } from './sql-utils';
|
|
@@ -29,6 +30,7 @@ export type PostgresContract = Contract<SqlStorage> & { readonly target: 'postgr
|
|
|
29
30
|
export type PostgresNamespaceEntries = SqlNamespaceEntries & {
|
|
30
31
|
readonly policy?: Readonly<Record<string, PostgresRlsPolicy>>;
|
|
31
32
|
readonly role?: Readonly<Record<string, PostgresRole>>;
|
|
33
|
+
readonly native_enum?: Readonly<Record<string, PostgresNativeEnum>>;
|
|
32
34
|
};
|
|
33
35
|
|
|
34
36
|
export interface PostgresSchemaInput {
|
|
@@ -70,7 +72,7 @@ export class PostgresSchema extends SqlNamespaceBase {
|
|
|
70
72
|
|
|
71
73
|
const dispatched = hydrateNamespaceEntities(
|
|
72
74
|
input.entries,
|
|
73
|
-
composeSqlEntityKinds([policyEntityKind, roleEntityKind]),
|
|
75
|
+
composeSqlEntityKinds([policyEntityKind, roleEntityKind, nativeEnumEntityKind]),
|
|
74
76
|
'carry',
|
|
75
77
|
);
|
|
76
78
|
|
|
@@ -81,11 +83,33 @@ export class PostgresSchema extends SqlNamespaceBase {
|
|
|
81
83
|
? { ...dispatched, valueSet: undefined }
|
|
82
84
|
: dispatched;
|
|
83
85
|
|
|
86
|
+
// `native_enum` is authoring-time-only (`PostgresContractSerializer`
|
|
87
|
+
// never re-emits it; its member values live on via the `valueSet`
|
|
88
|
+
// entry it derives). Carried as a non-enumerable property — like
|
|
89
|
+
// `kind` below — so `JSON.stringify` (the hashing pipeline's
|
|
90
|
+
// canonicalization step, `computeStorageHash` via `hashContract`)
|
|
91
|
+
// walks past it and the storage hash matches what actually gets
|
|
92
|
+
// serialized. Direct property access (`ns.entries.native_enum`)
|
|
93
|
+
// still resolves normally; only enumeration is affected.
|
|
94
|
+
const nativeEnumRaw = dispatched['native_enum'];
|
|
95
|
+
const entriesInput: Record<string, Readonly<Record<string, unknown>> | undefined> = {
|
|
96
|
+
...withPresence,
|
|
97
|
+
};
|
|
98
|
+
delete entriesInput['native_enum'];
|
|
99
|
+
if (nativeEnumRaw !== undefined) {
|
|
100
|
+
Object.defineProperty(entriesInput, 'native_enum', {
|
|
101
|
+
value: nativeEnumRaw,
|
|
102
|
+
enumerable: false,
|
|
103
|
+
writable: false,
|
|
104
|
+
configurable: true,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
84
108
|
this.entries = Object.freeze(
|
|
85
109
|
blindCast<
|
|
86
110
|
PostgresNamespaceEntries,
|
|
87
|
-
'composeSqlEntityKinds([policyEntityKind, roleEntityKind]) supplies table→StorageTable, valueSet→StorageValueSet, policy→PostgresRlsPolicy, role→PostgresRole descriptors'
|
|
88
|
-
>(
|
|
111
|
+
'composeSqlEntityKinds([policyEntityKind, roleEntityKind, nativeEnumEntityKind]) supplies table→StorageTable, valueSet→StorageValueSet, policy→PostgresRlsPolicy, role→PostgresRole, native_enum→PostgresNativeEnum descriptors'
|
|
112
|
+
>(entriesInput),
|
|
89
113
|
);
|
|
90
114
|
Object.defineProperty(this, 'kind', {
|
|
91
115
|
value: 'schema',
|
|
@@ -18,3 +18,10 @@ export const PostgresRlsPolicySchema = type({
|
|
|
18
18
|
'withCheck?': 'string',
|
|
19
19
|
permissive: 'boolean',
|
|
20
20
|
});
|
|
21
|
+
|
|
22
|
+
export const PostgresNativeEnumSchema = type({
|
|
23
|
+
kind: "'postgres-enum'",
|
|
24
|
+
typeName: 'string',
|
|
25
|
+
members: type.string.array().readonly(),
|
|
26
|
+
'control?': "'managed' | 'tolerated' | 'external' | 'observed'",
|
|
27
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ColumnDefault } from '@prisma-next/contract/types';
|
|
2
|
+
import type { SqlDescribedContractSpace } from '@prisma-next/family-sql/control';
|
|
2
3
|
import type {
|
|
3
4
|
DefaultMappingOptions,
|
|
4
5
|
PslNativeTypeAttribute,
|
|
@@ -7,6 +8,8 @@ import type {
|
|
|
7
8
|
RelationField,
|
|
8
9
|
} from '@prisma-next/family-sql/psl-infer';
|
|
9
10
|
import {
|
|
11
|
+
buildChildRelationField,
|
|
12
|
+
deriveRelationFieldName,
|
|
10
13
|
inferRelations,
|
|
11
14
|
mapDefault,
|
|
12
15
|
parseRawDefault,
|
|
@@ -14,6 +17,7 @@ import {
|
|
|
14
17
|
toModelName,
|
|
15
18
|
toNamedTypeName,
|
|
16
19
|
} from '@prisma-next/family-sql/psl-infer';
|
|
20
|
+
import { coordinateKey, elementCoordinates } from '@prisma-next/framework-components/ir';
|
|
17
21
|
import type {
|
|
18
22
|
PslAttribute,
|
|
19
23
|
PslAttributeArgument,
|
|
@@ -31,7 +35,15 @@ import {
|
|
|
31
35
|
makePslNamespaceEntries,
|
|
32
36
|
UNSPECIFIED_PSL_NAMESPACE_ID,
|
|
33
37
|
} from '@prisma-next/framework-components/psl-ast';
|
|
34
|
-
import type {
|
|
38
|
+
import type { SqlModelStorage } from '@prisma-next/sql-contract/types';
|
|
39
|
+
import type {
|
|
40
|
+
SqlColumnIR,
|
|
41
|
+
SqlForeignKeyIR,
|
|
42
|
+
SqlSchemaIR,
|
|
43
|
+
SqlTableIR,
|
|
44
|
+
} from '@prisma-next/sql-schema-ir/types';
|
|
45
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
46
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
35
47
|
import type { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
|
|
36
48
|
import { createPostgresDefaultMapping } from './postgres-default-mapping';
|
|
37
49
|
import { createPostgresTypeMap } from './postgres-type-map';
|
|
@@ -76,6 +88,179 @@ type TopLevelNameResult = {
|
|
|
76
88
|
readonly map?: string | undefined;
|
|
77
89
|
};
|
|
78
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Coordinates every element a set of already-assembled contracts declare,
|
|
93
|
+
* mapped to the {@link SqlDescribedContractSpace} that owns it and keyed by
|
|
94
|
+
* the shared {@link coordinateKey} helper. `contract infer` uses this to omit
|
|
95
|
+
* database elements a stack extension pack's contract space already
|
|
96
|
+
* describes — reusing the same coordinate walk the contract-space aggregate
|
|
97
|
+
* and cross-space collision check use (`elementCoordinates`), rather than a
|
|
98
|
+
* bespoke per-entity-kind membership test — and, for a foreign key whose
|
|
99
|
+
* referenced table an entry owns, to resolve the qualified cross-space
|
|
100
|
+
* relation it describes.
|
|
101
|
+
*/
|
|
102
|
+
function describedContractOwners(
|
|
103
|
+
describedContracts: readonly SqlDescribedContractSpace[],
|
|
104
|
+
): ReadonlyMap<string, SqlDescribedContractSpace> {
|
|
105
|
+
const owners = new Map<string, SqlDescribedContractSpace>();
|
|
106
|
+
for (const entry of describedContracts) {
|
|
107
|
+
for (const coordinate of elementCoordinates(entry.contract.storage)) {
|
|
108
|
+
owners.set(coordinateKey(coordinate), entry);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return owners;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The domain model a described contract maps a `(namespaceId, tableName)`
|
|
116
|
+
* storage coordinate to, plus the pack's own space id and column→field-name
|
|
117
|
+
* mapping — everything `buildModel`/`buildRelationField` need to emit the
|
|
118
|
+
* cross-space relation `<spaceId>:<namespaceId>.<modelName>` and resolve its
|
|
119
|
+
* `references` argument to the pack's own field names rather than a generic
|
|
120
|
+
* column-name guess.
|
|
121
|
+
*/
|
|
122
|
+
type CrossSpaceTarget = {
|
|
123
|
+
readonly spaceId: string;
|
|
124
|
+
readonly namespaceId: string;
|
|
125
|
+
readonly modelName: string;
|
|
126
|
+
readonly fieldNamesByColumn: TableColumnFieldNameMap;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
function resolveCrossSpaceTarget(
|
|
130
|
+
owner: SqlDescribedContractSpace,
|
|
131
|
+
namespaceId: string,
|
|
132
|
+
tableName: string,
|
|
133
|
+
): CrossSpaceTarget | undefined {
|
|
134
|
+
const domainNamespace = owner.contract.domain.namespaces[namespaceId];
|
|
135
|
+
if (domainNamespace === undefined) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (const [modelName, model] of Object.entries(domainNamespace.models)) {
|
|
140
|
+
const storage = blindCast<SqlModelStorage, 'SQL contract model storage'>(model.storage);
|
|
141
|
+
if (storage.namespaceId !== namespaceId || storage.table !== tableName) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const fieldNamesByColumn = new Map<string, ResolvedColumnFieldName>();
|
|
146
|
+
for (const [fieldName, fieldStorage] of Object.entries(storage.fields)) {
|
|
147
|
+
fieldNamesByColumn.set(fieldStorage.column, { fieldName });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { spaceId: owner.spaceId, namespaceId, modelName, fieldNamesByColumn };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
type ForeignKeyResolution = {
|
|
157
|
+
/** `tables`, with every cross-space or dangling foreign key removed. */
|
|
158
|
+
readonly tables: Record<string, SqlTableIR>;
|
|
159
|
+
/** Cross-space relation fields to merge onto `inferRelations`'s output, keyed by host table name. */
|
|
160
|
+
readonly extraRelationsByTable: ReadonlyMap<string, readonly RelationField[]>;
|
|
161
|
+
/** Synthetic field-name maps for cross-space-referenced pack tables, merged into `fieldNamesByTable`. */
|
|
162
|
+
readonly crossSpaceFieldNamesByTable: ReadonlyMap<string, TableColumnFieldNameMap>;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Classifies every foreign key on a surviving table into one of three cases.
|
|
167
|
+
* A foreign key that carries a `referencedSchema` is checked against the
|
|
168
|
+
* pack-owned coordinates first, so a pack-owned target wins even when a local
|
|
169
|
+
* table happens to share its bare name; only foreign keys with no owned
|
|
170
|
+
* coordinate fall through to the local/dangling distinction.
|
|
171
|
+
*
|
|
172
|
+
* - **Cross-space**: `referencedSchema` is set and a described contract owns
|
|
173
|
+
* the coordinate `(referencedSchema, 'table', referencedTable)`. The
|
|
174
|
+
* referenced table is absent from the tree (omitted because the pack
|
|
175
|
+
* describes it, or never introspected — `contract infer` walks a single
|
|
176
|
+
* namespace). Removed from `foreignKeys` (so `inferRelations` never falls
|
|
177
|
+
* back to a bare, unqualified table name for it) and replaced with a
|
|
178
|
+
* `RelationField` qualified with the owning pack's space id and namespace
|
|
179
|
+
* id. `owners` holds only pack-declared coordinates, so an app's own table
|
|
180
|
+
* (e.g. `public.users`) is never owned and cannot be captured here.
|
|
181
|
+
* - **Local**: not a pack-owned coordinate, and the referenced table survived
|
|
182
|
+
* introspection — left untouched, `inferRelations` handles it as before.
|
|
183
|
+
* - **Dangling**: not a pack-owned coordinate, and the referenced table is
|
|
184
|
+
* neither in the tree nor owned by any described contract. Removed from
|
|
185
|
+
* `foreignKeys`, keeping the scalar column, rather than emitting a relation
|
|
186
|
+
* to a model that was never defined.
|
|
187
|
+
*
|
|
188
|
+
* A pack that owns the referenced coordinate but declares no domain model
|
|
189
|
+
* mapped to it is malformed; that case throws rather than degrading to a
|
|
190
|
+
* silent drop, which would contradict the dangling definition above.
|
|
191
|
+
*/
|
|
192
|
+
function resolveForeignKeys(
|
|
193
|
+
tables: Readonly<Record<string, SqlTableIR>>,
|
|
194
|
+
owners: ReadonlyMap<string, SqlDescribedContractSpace>,
|
|
195
|
+
): ForeignKeyResolution {
|
|
196
|
+
const resultTables: Record<string, SqlTableIR> = {};
|
|
197
|
+
const extraRelationsByTable = new Map<string, RelationField[]>();
|
|
198
|
+
const crossSpaceFieldNamesByTable = new Map<string, TableColumnFieldNameMap>();
|
|
199
|
+
|
|
200
|
+
for (const [tableName, table] of Object.entries(tables)) {
|
|
201
|
+
const keptForeignKeys: SqlForeignKeyIR[] = [];
|
|
202
|
+
|
|
203
|
+
for (const fk of table.foreignKeys) {
|
|
204
|
+
if (fk.referencedSchema !== undefined) {
|
|
205
|
+
const owner = owners.get(
|
|
206
|
+
coordinateKey({
|
|
207
|
+
namespaceId: fk.referencedSchema,
|
|
208
|
+
entityKind: 'table',
|
|
209
|
+
entityName: fk.referencedTable,
|
|
210
|
+
}),
|
|
211
|
+
);
|
|
212
|
+
if (owner !== undefined) {
|
|
213
|
+
const target = resolveCrossSpaceTarget(owner, fk.referencedSchema, fk.referencedTable);
|
|
214
|
+
if (target === undefined) {
|
|
215
|
+
throw new Error(
|
|
216
|
+
`contract infer: described contract space "${owner.spaceId}" owns storage ` +
|
|
217
|
+
`coordinate "${fk.referencedSchema}.${fk.referencedTable}" but declares no ` +
|
|
218
|
+
'domain model mapped to it. A pack that describes a table must also declare the ' +
|
|
219
|
+
'domain model it maps to; this pack is malformed.',
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!crossSpaceFieldNamesByTable.has(fk.referencedTable)) {
|
|
224
|
+
crossSpaceFieldNamesByTable.set(fk.referencedTable, target.fieldNamesByColumn);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const fieldName = deriveRelationFieldName(fk.columns, fk.referencedTable);
|
|
228
|
+
const optional = fk.columns.some(
|
|
229
|
+
(columnName) => table.columns[columnName]?.nullable ?? false,
|
|
230
|
+
);
|
|
231
|
+
const relationField: RelationField = {
|
|
232
|
+
...buildChildRelationField(fieldName, target.modelName, fk, optional),
|
|
233
|
+
typeNamespaceId: target.namespaceId,
|
|
234
|
+
typeContractSpaceId: target.spaceId,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const existingRelations = extraRelationsByTable.get(tableName);
|
|
238
|
+
if (existingRelations) {
|
|
239
|
+
existingRelations.push(relationField);
|
|
240
|
+
} else {
|
|
241
|
+
extraRelationsByTable.set(tableName, [relationField]);
|
|
242
|
+
}
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Not a pack-owned coordinate: keep the foreign key if the referenced
|
|
248
|
+
// table survived introspection (local), otherwise drop it while keeping
|
|
249
|
+
// the scalar column (dangling).
|
|
250
|
+
if (tables[fk.referencedTable] !== undefined) {
|
|
251
|
+
keptForeignKeys.push(fk);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
resultTables[tableName] =
|
|
256
|
+
keptForeignKeys.length === table.foreignKeys.length
|
|
257
|
+
? table
|
|
258
|
+
: { ...table, foreignKeys: keptForeignKeys };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return { tables: resultTables, extraRelationsByTable, crossSpaceFieldNamesByTable };
|
|
262
|
+
}
|
|
263
|
+
|
|
79
264
|
/**
|
|
80
265
|
* Infers a PSL AST (for `printPsl`) from an introspected Postgres schema tree.
|
|
81
266
|
*
|
|
@@ -89,9 +274,23 @@ type TopLevelNameResult = {
|
|
|
89
274
|
* introspects a single live namespace) are gathered into the model set and
|
|
90
275
|
* emitted as one `UNSPECIFIED_PSL_NAMESPACE_ID` bucket. Top-level entities
|
|
91
276
|
* (policies/roles → PSL extension blocks) are a later slice.
|
|
277
|
+
*
|
|
278
|
+
* `describedContracts` — the stack's extension packs' already-assembled
|
|
279
|
+
* contracts, each paired with its space id — is consulted while gathering
|
|
280
|
+
* tables: a table whose coordinate `(schemaName, 'table', tableName)` one of
|
|
281
|
+
* those contracts already declares is omitted, before the duplicate-name
|
|
282
|
+
* check below and before relation inference, so it cannot spuriously
|
|
283
|
+
* collide with an app table and never contributes a bare relation field. A
|
|
284
|
+
* surviving table's foreign key into an omitted, pack-owned table is not
|
|
285
|
+
* dropped: {@link resolveForeignKeys} rewrites it into a relation qualified
|
|
286
|
+
* with the pack's space id (`<spaceId>:<namespaceId>.<Model>`) instead.
|
|
92
287
|
*/
|
|
93
|
-
export function inferPostgresPslContract(
|
|
288
|
+
export function inferPostgresPslContract(
|
|
289
|
+
tree: PostgresDatabaseSchemaNode,
|
|
290
|
+
describedContracts?: readonly SqlDescribedContractSpace[],
|
|
291
|
+
): PslDocumentAst {
|
|
94
292
|
const namespaces = Object.values(tree.namespaces);
|
|
293
|
+
const owners = describedContractOwners(describedContracts ?? []);
|
|
95
294
|
|
|
96
295
|
// Native Postgres enums (CREATE TYPE … AS ENUM) are not adoptable by
|
|
97
296
|
// `contract infer`; throw an actionable diagnostic naming the type(s). Enum
|
|
@@ -118,6 +317,17 @@ export function inferPostgresPslContract(tree: PostgresDatabaseSchemaNode): PslD
|
|
|
118
317
|
const tables: Record<string, SqlTableIR> = {};
|
|
119
318
|
for (const namespace of namespaces) {
|
|
120
319
|
for (const [tableName, table] of Object.entries(namespace.tables)) {
|
|
320
|
+
if (
|
|
321
|
+
owners.has(
|
|
322
|
+
coordinateKey({
|
|
323
|
+
namespaceId: namespace.schemaName,
|
|
324
|
+
entityKind: 'table',
|
|
325
|
+
entityName: tableName,
|
|
326
|
+
}),
|
|
327
|
+
)
|
|
328
|
+
) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
121
331
|
if (tables[tableName] !== undefined) {
|
|
122
332
|
throw new Error(
|
|
123
333
|
`contract infer: duplicate table name "${tableName}" across schemas is not yet supported ` +
|
|
@@ -128,7 +338,13 @@ export function inferPostgresPslContract(tree: PostgresDatabaseSchemaNode): PslD
|
|
|
128
338
|
tables[tableName] = table;
|
|
129
339
|
}
|
|
130
340
|
}
|
|
131
|
-
|
|
341
|
+
|
|
342
|
+
const {
|
|
343
|
+
tables: resolvedTables,
|
|
344
|
+
extraRelationsByTable,
|
|
345
|
+
crossSpaceFieldNamesByTable,
|
|
346
|
+
} = resolveForeignKeys(tables, owners);
|
|
347
|
+
const schemaIR: SqlSchemaIR = { tables: resolvedTables };
|
|
132
348
|
|
|
133
349
|
const options: PslPrinterOptions = {
|
|
134
350
|
typeMap: createPostgresTypeMap(new Set()),
|
|
@@ -136,11 +352,22 @@ export function inferPostgresPslContract(tree: PostgresDatabaseSchemaNode): PslD
|
|
|
136
352
|
parseRawDefault,
|
|
137
353
|
};
|
|
138
354
|
|
|
139
|
-
return buildPslDocumentAst(schemaIR, options
|
|
355
|
+
return buildPslDocumentAst(schemaIR, options, {
|
|
356
|
+
extraRelationsByTable,
|
|
357
|
+
crossSpaceFieldNamesByTable,
|
|
358
|
+
});
|
|
140
359
|
}
|
|
141
360
|
|
|
142
|
-
function buildPslDocumentAst(
|
|
361
|
+
function buildPslDocumentAst(
|
|
362
|
+
schemaIR: SqlSchemaIR,
|
|
363
|
+
options: PslPrinterOptions,
|
|
364
|
+
foreignKeyExtras: Pick<
|
|
365
|
+
ForeignKeyResolution,
|
|
366
|
+
'extraRelationsByTable' | 'crossSpaceFieldNamesByTable'
|
|
367
|
+
>,
|
|
368
|
+
): PslDocumentAst {
|
|
143
369
|
const { typeMap, defaultMapping, parseRawDefault: rawDefaultParser } = options;
|
|
370
|
+
const { extraRelationsByTable, crossSpaceFieldNamesByTable } = foreignKeyExtras;
|
|
144
371
|
|
|
145
372
|
const modelNames = buildTopLevelNameMap(
|
|
146
373
|
Object.keys(schemaIR.tables),
|
|
@@ -154,7 +381,14 @@ function buildPslDocumentAst(schemaIR: SqlSchemaIR, options: PslPrinterOptions):
|
|
|
154
381
|
);
|
|
155
382
|
const reservedNamedTypeNames = createReservedNamedTypeNames(modelNames);
|
|
156
383
|
|
|
157
|
-
|
|
384
|
+
// Cross-space entries are seeded first so a real local table of the same
|
|
385
|
+
// bare name (an existing single-namespace-flat-bucket limitation, not new
|
|
386
|
+
// here) always wins the merge, matching `resolveForeignKeys`'s own
|
|
387
|
+
// precedence: a surviving local table is never treated as cross-space.
|
|
388
|
+
const fieldNamesByTable = new Map([
|
|
389
|
+
...crossSpaceFieldNamesByTable,
|
|
390
|
+
...buildFieldNamesByTable(schemaIR.tables),
|
|
391
|
+
]);
|
|
158
392
|
const { relationsByTable } = inferRelations(schemaIR.tables, modelNameMap);
|
|
159
393
|
const namedTypes = seedNamedTypeRegistry(schemaIR, typeMap, new Map(), reservedNamedTypeNames);
|
|
160
394
|
|
|
@@ -169,7 +403,10 @@ function buildPslDocumentAst(schemaIR: SqlSchemaIR, options: PslPrinterOptions):
|
|
|
169
403
|
namedTypes,
|
|
170
404
|
defaultMapping,
|
|
171
405
|
rawDefaultParser,
|
|
172
|
-
|
|
406
|
+
[
|
|
407
|
+
...(relationsByTable.get(table.name) ?? []),
|
|
408
|
+
...(extraRelationsByTable.get(table.name) ?? []),
|
|
409
|
+
],
|
|
173
410
|
),
|
|
174
411
|
);
|
|
175
412
|
}
|
|
@@ -452,6 +689,8 @@ function buildRelationField(
|
|
|
452
689
|
kind: 'field',
|
|
453
690
|
name: fieldName,
|
|
454
691
|
typeName: rel.typeName,
|
|
692
|
+
...ifDefined('typeNamespaceId', rel.typeNamespaceId),
|
|
693
|
+
...ifDefined('typeContractSpaceId', rel.typeContractSpaceId),
|
|
455
694
|
optional: rel.optional,
|
|
456
695
|
list: rel.list,
|
|
457
696
|
attributes: attrs,
|
package/src/exports/control.ts
CHANGED
|
@@ -58,9 +58,9 @@ const postgresTargetDescriptor: SqlControlTargetDescriptor<'postgres', PostgresP
|
|
|
58
58
|
...postgresTargetDescriptorMeta,
|
|
59
59
|
contractSerializer: new PostgresContractSerializer(),
|
|
60
60
|
schemaVerifier: new PostgresSchemaVerifier(),
|
|
61
|
-
inferPslContract(schema) {
|
|
61
|
+
inferPslContract(schema, describedContracts) {
|
|
62
62
|
PostgresDatabaseSchemaNode.assert(schema);
|
|
63
|
-
return inferPostgresPslContract(schema);
|
|
63
|
+
return inferPostgresPslContract(schema, describedContracts);
|
|
64
64
|
},
|
|
65
65
|
diffDatabaseSchema(input) {
|
|
66
66
|
return diffPostgresDatabaseSchema({
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import { c as PostgresRlsPolicySchema, d as PostgresRlsPolicy, l as PostgresRoleSchema, u as PostgresRole } from "./postgres-schema-BLIHBEfX.mjs";
|
|
2
|
-
import { n as normalizePredicate, t as computeContentHash } from "./canonicalize-Bn3BM1Cn.mjs";
|
|
3
|
-
import { temporalAuthoringPresets } from "@prisma-next/family-sql/control";
|
|
4
|
-
//#region src/core/authoring.ts
|
|
5
|
-
const postgresAuthoringTypes = {};
|
|
6
|
-
function readRefParam(block, key) {
|
|
7
|
-
const param = block.parameters[key];
|
|
8
|
-
return param?.kind === "ref" ? param.identifier : void 0;
|
|
9
|
-
}
|
|
10
|
-
function readValueParam(block, key) {
|
|
11
|
-
const param = block.parameters[key];
|
|
12
|
-
return param?.kind === "value" ? param.raw : void 0;
|
|
13
|
-
}
|
|
14
|
-
function readListRefParams(block, key) {
|
|
15
|
-
const param = block.parameters[key];
|
|
16
|
-
if (param?.kind !== "list") return [];
|
|
17
|
-
return param.items.flatMap((item) => item.kind === "ref" ? [item.identifier] : []);
|
|
18
|
-
}
|
|
19
|
-
function unwrapQuotedString(raw) {
|
|
20
|
-
if (raw.startsWith("\"") && raw.endsWith("\"") && raw.length >= 2) return raw.slice(1, -1).replace(/\\"/g, "\"");
|
|
21
|
-
return raw;
|
|
22
|
-
}
|
|
23
|
-
function lowerRlsPolicyFromBlock(block, _ctx) {
|
|
24
|
-
const prefix = block.name;
|
|
25
|
-
const targetModelName = readRefParam(block, "target") ?? "";
|
|
26
|
-
const tableName = targetModelName.charAt(0).toLowerCase() + targetModelName.slice(1);
|
|
27
|
-
const roles = [...readListRefParams(block, "roles")].sort();
|
|
28
|
-
const using = unwrapQuotedString(readValueParam(block, "using") ?? "");
|
|
29
|
-
return new PostgresRlsPolicy({
|
|
30
|
-
name: `${prefix}_${computeContentHash({
|
|
31
|
-
using: normalizePredicate(using),
|
|
32
|
-
roles,
|
|
33
|
-
operation: "select",
|
|
34
|
-
permissive: true
|
|
35
|
-
})}`,
|
|
36
|
-
prefix,
|
|
37
|
-
tableName,
|
|
38
|
-
namespaceId: block.namespaceId,
|
|
39
|
-
operation: "select",
|
|
40
|
-
roles,
|
|
41
|
-
using,
|
|
42
|
-
permissive: true
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
const postgresAuthoringEntityTypes = {
|
|
46
|
-
role: {
|
|
47
|
-
kind: "entity",
|
|
48
|
-
discriminator: "role",
|
|
49
|
-
validatorSchema: PostgresRoleSchema,
|
|
50
|
-
output: { factory: (input) => new PostgresRole(input) }
|
|
51
|
-
},
|
|
52
|
-
policy: {
|
|
53
|
-
kind: "entity",
|
|
54
|
-
discriminator: "policy",
|
|
55
|
-
validatorSchema: PostgresRlsPolicySchema,
|
|
56
|
-
output: { factory: lowerRlsPolicyFromBlock }
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
/**
|
|
60
|
-
* Field presets contributed by the Postgres target pack.
|
|
61
|
-
*
|
|
62
|
-
* These mirror the PSL scalar-to-codec mapping used by the Postgres adapter
|
|
63
|
-
* (see `createPostgresPslScalarTypeDescriptors`), so that authoring a field
|
|
64
|
-
* via the TS callback surface (e.g. `field.int()`) and via the PSL scalar
|
|
65
|
-
* surface (e.g. `Int`) lowers to byte-identical contracts.
|
|
66
|
-
*
|
|
67
|
-
* The `uuidNative` / `id.uuidv4Native` / `id.uuidv7Native` presets use the
|
|
68
|
-
* native Postgres `uuid` type (codecId `pg/uuid@1`). For cross-target
|
|
69
|
-
* portability use `uuidString` / `id.uuidv4String` / `id.uuidv7String` from
|
|
70
|
-
* the family pack instead.
|
|
71
|
-
*/
|
|
72
|
-
/**
|
|
73
|
-
* PSL block descriptor for `policy_select`.
|
|
74
|
-
*
|
|
75
|
-
* The parser learns the block shape from this descriptor; lowering from
|
|
76
|
-
* `PslExtensionBlock` to `PostgresRlsPolicy` is wired in the PSL
|
|
77
|
-
* interpreter (a later dispatch). The `discriminator` matches
|
|
78
|
-
* `PostgresRlsPolicy.kind` so the parsed block node carries the same
|
|
79
|
-
* discriminant as the IR class it will lower to.
|
|
80
|
-
*
|
|
81
|
-
* The `roles` list uses `scope:'cross-space'` because same-namespace
|
|
82
|
-
* role ref resolution requires PSL namespace entries keyed by `refKind`
|
|
83
|
-
* (i.e. `'role'`), which in turn requires the role block discriminator to
|
|
84
|
-
* equal `'role'`. Aligning discriminator with refKind is tracked for
|
|
85
|
-
* slice 4 (cross-space roles). Until then cross-space passes validation
|
|
86
|
-
* unconditionally and the authored role names flow through unchanged.
|
|
87
|
-
*/
|
|
88
|
-
const postgresAuthoringPslBlockDescriptors = { policy_select: {
|
|
89
|
-
kind: "pslBlock",
|
|
90
|
-
keyword: "policy_select",
|
|
91
|
-
discriminator: "policy",
|
|
92
|
-
name: { required: true },
|
|
93
|
-
parameters: {
|
|
94
|
-
target: {
|
|
95
|
-
kind: "ref",
|
|
96
|
-
refKind: "model",
|
|
97
|
-
scope: "same-namespace",
|
|
98
|
-
required: true
|
|
99
|
-
},
|
|
100
|
-
roles: {
|
|
101
|
-
kind: "list",
|
|
102
|
-
of: {
|
|
103
|
-
kind: "ref",
|
|
104
|
-
refKind: "role",
|
|
105
|
-
scope: "cross-space"
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
using: {
|
|
109
|
-
kind: "value",
|
|
110
|
-
codecId: "pg/text@1",
|
|
111
|
-
required: true
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
} };
|
|
115
|
-
const postgresAuthoringFieldPresets = {
|
|
116
|
-
text: {
|
|
117
|
-
kind: "fieldPreset",
|
|
118
|
-
output: {
|
|
119
|
-
codecId: "pg/text@1",
|
|
120
|
-
nativeType: "text"
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
int: {
|
|
124
|
-
kind: "fieldPreset",
|
|
125
|
-
output: {
|
|
126
|
-
codecId: "pg/int4@1",
|
|
127
|
-
nativeType: "int4"
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
bigint: {
|
|
131
|
-
kind: "fieldPreset",
|
|
132
|
-
output: {
|
|
133
|
-
codecId: "pg/int8@1",
|
|
134
|
-
nativeType: "int8"
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
float: {
|
|
138
|
-
kind: "fieldPreset",
|
|
139
|
-
output: {
|
|
140
|
-
codecId: "pg/float8@1",
|
|
141
|
-
nativeType: "float8"
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
decimal: {
|
|
145
|
-
kind: "fieldPreset",
|
|
146
|
-
output: {
|
|
147
|
-
codecId: "pg/numeric@1",
|
|
148
|
-
nativeType: "numeric"
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
boolean: {
|
|
152
|
-
kind: "fieldPreset",
|
|
153
|
-
output: {
|
|
154
|
-
codecId: "pg/bool@1",
|
|
155
|
-
nativeType: "bool"
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
json: {
|
|
159
|
-
kind: "fieldPreset",
|
|
160
|
-
output: {
|
|
161
|
-
codecId: "pg/jsonb@1",
|
|
162
|
-
nativeType: "jsonb"
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
bytes: {
|
|
166
|
-
kind: "fieldPreset",
|
|
167
|
-
output: {
|
|
168
|
-
codecId: "pg/bytea@1",
|
|
169
|
-
nativeType: "bytea"
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
dateTime: {
|
|
173
|
-
kind: "fieldPreset",
|
|
174
|
-
output: {
|
|
175
|
-
codecId: "pg/timestamptz@1",
|
|
176
|
-
nativeType: "timestamptz"
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
temporal: /* @__PURE__ */ temporalAuthoringPresets({
|
|
180
|
-
codecId: "pg/timestamptz@1",
|
|
181
|
-
nativeType: "timestamptz"
|
|
182
|
-
}),
|
|
183
|
-
uuidNative: {
|
|
184
|
-
kind: "fieldPreset",
|
|
185
|
-
output: {
|
|
186
|
-
codecId: "pg/uuid@1",
|
|
187
|
-
nativeType: "uuid"
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
id: {
|
|
191
|
-
uuidv4Native: {
|
|
192
|
-
kind: "fieldPreset",
|
|
193
|
-
output: {
|
|
194
|
-
codecId: "pg/uuid@1",
|
|
195
|
-
nativeType: "uuid",
|
|
196
|
-
executionDefaults: { onCreate: {
|
|
197
|
-
kind: "generator",
|
|
198
|
-
id: "uuidv4"
|
|
199
|
-
} },
|
|
200
|
-
id: true
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
uuidv7Native: {
|
|
204
|
-
kind: "fieldPreset",
|
|
205
|
-
output: {
|
|
206
|
-
codecId: "pg/uuid@1",
|
|
207
|
-
nativeType: "uuid",
|
|
208
|
-
executionDefaults: { onCreate: {
|
|
209
|
-
kind: "generator",
|
|
210
|
-
id: "uuidv7"
|
|
211
|
-
} },
|
|
212
|
-
id: true
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
//#endregion
|
|
218
|
-
export { postgresAuthoringTypes as i, postgresAuthoringFieldPresets as n, postgresAuthoringPslBlockDescriptors as r, postgresAuthoringEntityTypes as t };
|
|
219
|
-
|
|
220
|
-
//# sourceMappingURL=authoring-BX1WHIdN.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"authoring-BX1WHIdN.mjs","names":[],"sources":["../src/core/authoring.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"],"mappings":";;;;AAcA,MAAa,yBAAyB,CAAC;AAMvC,SAAS,aAAa,OAA0B,KAAiC;CAC/E,MAAM,QAAQ,MAAM,WAAW;CAC/B,OAAO,OAAO,SAAS,QAAQ,MAAM,aAAa,KAAA;AACpD;AAEA,SAAS,eAAe,OAA0B,KAAiC;CACjF,MAAM,QAAQ,MAAM,WAAW;CAC/B,OAAO,OAAO,SAAS,UAAU,MAAM,MAAM,KAAA;AAC/C;AAEA,SAAS,kBAAkB,OAA0B,KAAuB;CAC1E,MAAM,QAAQ,MAAM,WAAW;CAC/B,IAAI,OAAO,SAAS,QAAQ,OAAO,CAAC;CACpC,OAAO,MAAM,MAAM,SAAS,SAAU,KAAK,SAAS,QAAQ,CAAC,KAAK,UAAU,IAAI,CAAC,CAAE;AACrF;AAEA,SAAS,mBAAmB,KAAqB;CAC/C,IAAI,IAAI,WAAW,IAAG,KAAK,IAAI,SAAS,IAAG,KAAK,IAAI,UAAU,GAC5D,OAAO,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC,QAAQ,QAAQ,IAAG;CAE7C,OAAO;AACT;AAEA,SAAS,wBACP,OACA,MACmB;CACnB,MAAM,SAAS,MAAM;CACrB,MAAM,kBAAkB,aAAa,OAAO,QAAQ,KAAK;CACzD,MAAM,YAAY,gBAAgB,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,gBAAgB,MAAM,CAAC;CACnF,MAAM,QAAQ,CAAC,GAAG,kBAAkB,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK;CAC1D,MAAM,QAAQ,mBAAmB,eAAe,OAAO,OAAO,KAAK,EAAE;CAUrE,OAAO,IAAI,kBAAkB;EAC3B,MAAM,GAHY,OAAO,GANV,mBAAmB;GAClC,OAAO,mBAAmB,KAAK;GAC/B;GACA,WAAW;GACX,YAAY;EACd,CACqC;EAInC;EACA;EACA,aAAa,MAAM;EACnB,WAAW;EACX;EACA;EACA,YAAY;CACd,CAAC;AACH;AAEA,MAAa,+BAA+B;CAC1C,MAAM;EACJ,MAAM;EACN,eAAe;EACf,iBAAiB;EACjB,QAAQ,EACN,UAAU,UAA2C,IAAI,aAAa,KAAK,EAC7E;CACF;CACA,QAAQ;EACN,MAAM;EACN,eAAe;EACf,iBAAiB;EACjB,QAAQ,EACN,SAAS,wBACX;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAa,uCAAuC,EAClD,eAAe;CACb,MAAM;CACN,SAAS;CACT,eAAe;CACf,MAAM,EAAE,UAAU,KAAK;CACvB,YAAY;EACV,QAAQ;GAAE,MAAM;GAAO,SAAS;GAAS,OAAO;GAAkB,UAAU;EAAK;EACjF,OAAO;GACL,MAAM;GACN,IAAI;IAAE,MAAM;IAAO,SAAS;IAAQ,OAAO;GAAc;EAC3D;EACA,OAAO;GAAE,MAAM;GAAS,SAAS;GAAa,UAAU;EAAK;CAC/D;AACF,EACF;AAEA,MAAa,gCAAgC;CAC3C,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,KAAK;EACH,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,QAAQ;EACN,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAAU;EACR,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAA0B,yCAAyB;EACjD,SAAS;EACT,YAAY;CACd,CAAC;CACD,YAAY;EACV,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,IAAI;EACF,cAAc;GACZ,MAAM;GACN,QAAQ;IACN,SAAS;IACT,YAAY;IACZ,mBAAmB,EACjB,UAAU;KACR,MAAM;KACN,IAAI;IACN,EACF;IACA,IAAI;GACN;EACF;EACA,cAAc;GACZ,MAAM;GACN,QAAQ;IACN,SAAS;IACT,YAAY;IACZ,mBAAmB,EACjB,UAAU;KACR,MAAM;KACN,IAAI;IACN,EACF;IACA,IAAI;GACN;EACF;CACF;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codec-ids-BvytN2P8.mjs","names":[],"sources":["../src/core/codec-ids.ts"],"sourcesContent":["export {\n SQL_CHAR_CODEC_ID,\n SQL_FLOAT_CODEC_ID,\n SQL_INT_CODEC_ID,\n SQL_TEXT_CODEC_ID,\n SQL_TIMESTAMP_CODEC_ID,\n SQL_VARCHAR_CODEC_ID,\n} from '@prisma-next/sql-relational-core/ast';\nexport const PG_TEXT_CODEC_ID = 'pg/text@1' as const;\nexport const PG_TEXT_ARRAY_CODEC_ID = 'pg/text-array@1' as const;\nexport const PG_CHAR_CODEC_ID = 'pg/char@1' as const;\nexport const PG_VARCHAR_CODEC_ID = 'pg/varchar@1' as const;\nexport const PG_INT_CODEC_ID = 'pg/int@1' as const;\nexport const PG_INT2_CODEC_ID = 'pg/int2@1' as const;\nexport const PG_INT4_CODEC_ID = 'pg/int4@1' as const;\nexport const PG_INT8_CODEC_ID = 'pg/int8@1' as const;\nexport const PG_FLOAT_CODEC_ID = 'pg/float@1' as const;\nexport const PG_FLOAT4_CODEC_ID = 'pg/float4@1' as const;\nexport const PG_FLOAT8_CODEC_ID = 'pg/float8@1' as const;\nexport const PG_NUMERIC_CODEC_ID = 'pg/numeric@1' as const;\nexport const PG_BOOL_CODEC_ID = 'pg/bool@1' as const;\nexport const PG_BIT_CODEC_ID = 'pg/bit@1' as const;\nexport const PG_VARBIT_CODEC_ID = 'pg/varbit@1' as const;\nexport const PG_TIMESTAMP_CODEC_ID = 'pg/timestamp@1' as const;\nexport const PG_TIMESTAMPTZ_CODEC_ID = 'pg/timestamptz@1' as const;\nexport const PG_TIME_CODEC_ID = 'pg/time@1' as const;\nexport const PG_TIMETZ_CODEC_ID = 'pg/timetz@1' as const;\nexport const PG_INTERVAL_CODEC_ID = 'pg/interval@1' as const;\nexport const PG_JSON_CODEC_ID = 'pg/json@1' as const;\nexport const PG_JSONB_CODEC_ID = 'pg/jsonb@1' as const;\nexport const PG_BYTEA_CODEC_ID = 'pg/bytea@1' as const;\nexport const PG_UUID_CODEC_ID = 'pg/uuid@1' as const;\n"],"mappings":";;AAQA,MAAa,mBAAmB;AAChC,MAAa,yBAAyB;AACtC,MAAa,mBAAmB;AAChC,MAAa,sBAAsB;AACnC,MAAa,kBAAkB;AAC/B,MAAa,mBAAmB;AAChC,MAAa,mBAAmB;AAChC,MAAa,mBAAmB;AAChC,MAAa,oBAAoB;AACjC,MAAa,qBAAqB;AAClC,MAAa,qBAAqB;AAClC,MAAa,sBAAsB;AACnC,MAAa,mBAAmB;AAChC,MAAa,kBAAkB;AAC/B,MAAa,qBAAqB;AAClC,MAAa,wBAAwB;AACrC,MAAa,0BAA0B;AACvC,MAAa,mBAAmB;AAChC,MAAa,qBAAqB;AAClC,MAAa,uBAAuB;AACpC,MAAa,mBAAmB;AAChC,MAAa,oBAAoB;AACjC,MAAa,oBAAoB;AACjC,MAAa,mBAAmB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codec-ids-CnXu9Qy3.d.mts","names":[],"sources":["../src/core/codec-ids.ts"],"mappings":";;;cAQa,gBAAA;AAAA,cACA,sBAAA;AAAA,cACA,gBAAA;AAAA,cACA,mBAAA;AAAA,cACA,eAAA;AAAA,cACA,gBAAA;AAAA,cACA,gBAAA;AAAA,cACA,gBAAA;AAAA,cACA,iBAAA;AAAA,cACA,kBAAA;AAAA,cACA,kBAAA;AAAA,cACA,mBAAA;AAAA,cACA,gBAAA;AAAA,cACA,eAAA;AAAA,cACA,kBAAA;AAAA,cACA,qBAAA;AAAA,cACA,uBAAA;AAAA,cACA,gBAAA;AAAA,cACA,kBAAA;AAAA,cACA,oBAAA;AAAA,cACA,gBAAA;AAAA,cACA,iBAAA;AAAA,cACA,iBAAA;AAAA,cACA,gBAAA"}
|