@prisma-next/target-postgres 0.14.0-dev.7 → 0.14.0-dev.70
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-Bi9aa8zG.mjs +574 -0
- package/dist/authoring-Bi9aa8zG.mjs.map +1 -0
- package/dist/canonicalize-CAbXtVtB.d.mts +37 -0
- package/dist/canonicalize-CAbXtVtB.d.mts.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-DHCkwPKE.d.mts → codec-types-BiIWziRO.d.mts} +3 -2
- package/dist/codec-types-BiIWziRO.d.mts.map +1 -0
- package/dist/codec-types.d.mts +1 -1
- package/dist/codecs-Cl_hQHg-.mjs +913 -0
- package/dist/codecs-Cl_hQHg-.mjs.map +1 -0
- package/dist/{codecs--0A5_4Bq.d.mts → codecs-Cm-nS4mQ.d.mts} +111 -4
- package/dist/codecs-Cm-nS4mQ.d.mts.map +1 -0
- package/dist/codecs.d.mts +2 -2
- package/dist/codecs.mjs +3 -757
- package/dist/codecs.mjs.map +1 -1
- package/dist/contract-free.d.mts +33 -3
- package/dist/contract-free.d.mts.map +1 -1
- package/dist/contract-free.mjs +23 -7
- package/dist/contract-free.mjs.map +1 -1
- package/dist/control-policy-5_5odTg9.mjs +1258 -0
- package/dist/control-policy-5_5odTg9.mjs.map +1 -0
- package/dist/control.d.mts +2 -2
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +866 -36
- package/dist/control.mjs.map +1 -1
- package/dist/data-transform-BOWpliq8.mjs.map +1 -1
- package/dist/{data-transform-DDgWdB5o.d.mts → data-transform-DPzwBMhW.d.mts} +3 -3
- package/dist/{data-transform-DDgWdB5o.d.mts.map → data-transform-DPzwBMhW.d.mts.map} +1 -1
- package/dist/data-transform.d.mts +1 -1
- package/dist/{ddl-QDyOSeLc.mjs → ddl-Dqgs-bDc.mjs} +93 -6
- package/dist/ddl-Dqgs-bDc.mjs.map +1 -0
- package/dist/ddl.d.mts +3 -2
- package/dist/ddl.mjs +2 -2
- package/dist/default-normalizer.d.mts +1 -1
- package/dist/default-normalizer.d.mts.map +1 -1
- package/dist/default-normalizer.mjs +247 -1
- package/dist/default-normalizer.mjs.map +1 -0
- package/dist/descriptor-meta-UugzVM-U.mjs +22 -0
- package/dist/descriptor-meta-UugzVM-U.mjs.map +1 -0
- package/dist/descriptor-meta-runtime-UwYdV8fD.mjs +12 -0
- package/dist/descriptor-meta-runtime-UwYdV8fD.mjs.map +1 -0
- package/dist/diff-database-schema-Dis8SMoT.mjs +305 -0
- package/dist/diff-database-schema-Dis8SMoT.mjs.map +1 -0
- package/dist/diff-database-schema.d.mts +46 -0
- package/dist/diff-database-schema.d.mts.map +1 -0
- package/dist/diff-database-schema.mjs +2 -0
- package/dist/errors-DO-w0EUS.mjs +35 -0
- package/dist/errors-DO-w0EUS.mjs.map +1 -0
- package/dist/errors.d.mts +11 -9
- package/dist/errors.d.mts.map +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/issue-planner.d.mts +35 -11
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +2 -2
- package/dist/migration.d.mts +5 -5
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +4 -4
- package/dist/namespace-ids-xtp_ZY86.mjs +7 -0
- package/dist/namespace-ids-xtp_ZY86.mjs.map +1 -0
- package/dist/native-type-normalizer.mjs +37 -1
- package/dist/native-type-normalizer.mjs.map +1 -0
- package/dist/nodes-Bc2N3tMy.d.mts +170 -0
- package/dist/nodes-Bc2N3tMy.d.mts.map +1 -0
- package/dist/nodes-DJC5B8Id.mjs +192 -0
- package/dist/nodes-DJC5B8Id.mjs.map +1 -0
- package/dist/{op-factory-call-DmQEc3XV.d.mts → op-factory-call-CSIg5XDu.d.mts} +91 -15
- package/dist/op-factory-call-CSIg5XDu.d.mts.map +1 -0
- package/dist/{op-factory-call-D_p5vxwt.mjs → op-factory-call-WFZUHrbI.mjs} +400 -32
- package/dist/op-factory-call-WFZUHrbI.mjs.map +1 -0
- package/dist/op-factory-call.d.mts +2 -2
- package/dist/op-factory-call.mjs +2 -2
- package/dist/pack.d.mts +300 -3
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/planner-BXlWpNsT.mjs +390 -0
- package/dist/planner-BXlWpNsT.mjs.map +1 -0
- package/dist/{planner-ddl-builders-B2wOwLqI.mjs → planner-ddl-builders-BKlmGDJl.mjs} +17 -28
- package/dist/planner-ddl-builders-BKlmGDJl.mjs.map +1 -0
- package/dist/planner-ddl-builders.d.mts +4 -6
- package/dist/planner-ddl-builders.d.mts.map +1 -1
- package/dist/planner-ddl-builders.mjs +2 -2
- package/dist/planner-identity-values-CJPha2Sz.mjs.map +1 -1
- package/dist/planner-identity-values.d.mts +8 -2
- package/dist/planner-identity-values.d.mts.map +1 -1
- package/dist/planner-identity-values.mjs +2 -2
- package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs → planner-produced-postgres-migration-C8vSaHku.mjs} +3 -3
- package/dist/{planner-produced-postgres-migration-Cji5vxUf.mjs.map → planner-produced-postgres-migration-C8vSaHku.mjs.map} +1 -1
- package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts → planner-produced-postgres-migration-CXue-6M9.d.mts} +4 -4
- package/dist/{planner-produced-postgres-migration-QqHa2C2l.d.mts.map → planner-produced-postgres-migration-CXue-6M9.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-jqUUGyQR.mjs → planner-sql-checks-CxJ8W66T.mjs} +3 -3
- package/dist/{planner-sql-checks-jqUUGyQR.mjs.map → planner-sql-checks-CxJ8W66T.mjs.map} +1 -1
- package/dist/planner-sql-checks.d.mts +2 -2
- package/dist/planner-sql-checks.d.mts.map +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/{planner-target-details-CIY6tLeo.d.mts → planner-target-details-HkP4RrRO.d.mts} +2 -2
- package/dist/planner-target-details-HkP4RrRO.d.mts.map +1 -0
- package/dist/planner-target-details.d.mts +1 -1
- package/dist/planner.d.mts +72 -17
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +3 -2
- package/dist/{postgres-contract-serializer-k3TAcPMY.mjs → postgres-contract-view-C3LPCLP_.mjs} +45 -41
- package/dist/postgres-contract-view-C3LPCLP_.mjs.map +1 -0
- package/dist/postgres-contract-view-C9j5cqP0.d.mts +34 -0
- package/dist/postgres-contract-view-C9j5cqP0.d.mts.map +1 -0
- package/dist/postgres-database-schema-node-CJv5bfbs.d.mts +262 -0
- package/dist/postgres-database-schema-node-CJv5bfbs.d.mts.map +1 -0
- package/dist/{postgres-migration-B5jKrXv3.mjs → postgres-migration-B3u0erMT.mjs} +69 -45
- package/dist/postgres-migration-B3u0erMT.mjs.map +1 -0
- package/dist/{postgres-migration-Y4YBJqkS.d.mts → postgres-migration-DkmgGNcv.d.mts} +47 -9
- package/dist/postgres-migration-DkmgGNcv.d.mts.map +1 -0
- package/dist/postgres-native-enum-BwVNf0Ku.mjs +45 -0
- package/dist/postgres-native-enum-BwVNf0Ku.mjs.map +1 -0
- package/dist/postgres-rls-policy--CSddvMR.d.mts +52 -0
- package/dist/postgres-rls-policy--CSddvMR.d.mts.map +1 -0
- package/dist/postgres-role-schema-node-Cm-j0ZGM.mjs +190 -0
- package/dist/postgres-role-schema-node-Cm-j0ZGM.mjs.map +1 -0
- package/dist/postgres-schema-DKq6s1P3.d.mts +269 -0
- package/dist/postgres-schema-DKq6s1P3.d.mts.map +1 -0
- package/dist/{postgres-schema-COGZ1ark.mjs → postgres-schema-DYATroNx.mjs} +200 -11
- package/dist/postgres-schema-DYATroNx.mjs.map +1 -0
- package/dist/postgres-table-schema-node-D6LvInCe.mjs +216 -0
- package/dist/postgres-table-schema-node-D6LvInCe.mjs.map +1 -0
- package/dist/render-ops.d.mts +1 -1
- package/dist/{render-typescript-KMgosran.mjs → render-typescript-7yqILcwr.mjs} +45 -16
- package/dist/render-typescript-7yqILcwr.mjs.map +1 -0
- package/dist/render-typescript.mjs +1 -1
- package/dist/resolve-ddl-schema-DpGte50u.mjs +22 -0
- package/dist/resolve-ddl-schema-DpGte50u.mjs.map +1 -0
- package/dist/rls-canonicalize.d.mts +20 -0
- package/dist/rls-canonicalize.d.mts.map +1 -0
- package/dist/rls-canonicalize.mjs +2 -0
- package/dist/runtime.d.mts +6 -8
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +3 -3
- package/dist/runtime.mjs.map +1 -1
- package/dist/schema-ir-annotations.d.mts +15 -0
- package/dist/schema-ir-annotations.d.mts.map +1 -0
- package/dist/schema-ir-annotations.mjs +2 -0
- package/dist/{sql-utils-DcfMz4MQ.mjs → sql-utils-SU4FDvIV.mjs} +12 -3
- package/dist/{sql-utils-DcfMz4MQ.mjs.map → sql-utils-SU4FDvIV.mjs.map} +1 -1
- package/dist/sql-utils.d.mts +8 -1
- package/dist/sql-utils.d.mts.map +1 -1
- package/dist/sql-utils.mjs +2 -2
- package/dist/types.d.mts +4 -140
- package/dist/types.mjs +5 -2
- package/dist/wire-name-rHHtr1h0.mjs +75 -0
- package/dist/wire-name-rHHtr1h0.mjs.map +1 -0
- package/package.json +23 -17
- package/src/contract-free/checks.ts +73 -0
- package/src/contract-free/control-bootstrap.ts +20 -3
- package/src/contract-free/ddl.ts +98 -1
- package/src/core/authoring.ts +509 -2
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codec-type-map.ts +2 -0
- package/src/core/codecs.ts +180 -1
- package/src/core/ddl/nodes.ts +185 -2
- package/src/core/default-normalizer.ts +122 -2
- package/src/core/descriptor-meta.ts +10 -1
- package/src/core/entity-kinds.ts +41 -0
- package/src/core/errors.ts +14 -12
- package/src/core/migrations/bound-schema.ts +10 -0
- package/src/core/migrations/column-ddl-rendering.ts +117 -0
- package/src/core/migrations/contract-to-postgres-database-schema-node.ts +189 -0
- package/src/core/migrations/control-policy.ts +217 -65
- package/src/core/migrations/diff-database-schema.ts +252 -0
- package/src/core/migrations/issue-planner.ts +769 -656
- package/src/core/migrations/op-factory-call.ts +273 -21
- package/src/core/migrations/operations/columns.ts +24 -12
- package/src/core/migrations/operations/constraints.ts +1 -1
- package/src/core/migrations/operations/data-transform.ts +6 -0
- package/src/core/migrations/operations/dependencies.ts +2 -1
- package/src/core/migrations/operations/native-enum-types.ts +62 -0
- package/src/core/migrations/operations/rls.ts +187 -0
- package/src/core/migrations/operations/shared.ts +0 -30
- package/src/core/migrations/planner-ddl-builders.ts +31 -59
- package/src/core/migrations/planner-identity-values.ts +1 -1
- package/src/core/migrations/planner-recipes.ts +31 -13
- package/src/core/migrations/planner-sql-checks.ts +1 -1
- package/src/core/migrations/planner-strategies.ts +248 -216
- package/src/core/migrations/planner-target-details.ts +3 -1
- package/src/core/migrations/planner.ts +357 -67
- package/src/core/migrations/postgres-migration.ts +101 -86
- package/src/core/migrations/render-typescript.ts +42 -15
- package/src/core/migrations/resolve-ddl-schema.ts +26 -0
- package/src/core/migrations/runner.ts +11 -16
- package/src/core/migrations/verify-postgres-namespaces.ts +46 -31
- package/src/core/namespace-ids.ts +3 -0
- package/src/core/postgres-contract-serializer.ts +46 -71
- package/src/core/postgres-contract-view.ts +48 -0
- package/src/core/postgres-native-enum.ts +61 -0
- package/src/core/postgres-rls-enablement.ts +34 -0
- package/src/core/postgres-rls-policy.ts +64 -0
- package/src/core/postgres-role.ts +59 -0
- package/src/core/postgres-schema-verifier.ts +10 -7
- package/src/core/postgres-schema.ts +85 -15
- package/src/core/postgres-validators.ts +34 -0
- package/src/core/psl-infer/infer-psl-contract.ts +1273 -0
- package/src/core/psl-infer/postgres-default-mapping.ts +16 -0
- package/src/core/psl-infer/postgres-type-map.ts +128 -0
- package/src/core/rls/canonicalize.ts +48 -0
- package/src/core/rls/wire-name.ts +33 -0
- package/src/core/schema-ir/node-storage-coordinate.ts +26 -0
- package/src/core/schema-ir/postgres-database-schema-node.ts +61 -0
- package/src/core/schema-ir/postgres-namespace-schema-node.ts +70 -0
- package/src/core/schema-ir/postgres-native-enum-schema-node.ts +83 -0
- package/src/core/schema-ir/postgres-policy-schema-node.ts +90 -0
- package/src/core/schema-ir/postgres-role-schema-node.ts +65 -0
- package/src/core/schema-ir/postgres-table-schema-node.ts +140 -0
- package/src/core/schema-ir/schema-node-kinds.ts +122 -0
- package/src/core/sql-utils.ts +15 -2
- package/src/exports/codecs.ts +3 -0
- package/src/exports/contract-free.ts +11 -1
- package/src/exports/control.ts +27 -33
- package/src/exports/ddl.ts +8 -0
- package/src/exports/diff-database-schema.ts +7 -0
- package/src/exports/issue-planner.ts +1 -1
- package/src/exports/migration.ts +1 -0
- package/src/exports/op-factory-call.ts +3 -0
- package/src/exports/planner-ddl-builders.ts +0 -2
- package/src/exports/planner-identity-values.ts +4 -1
- package/src/exports/planner.ts +1 -0
- package/src/exports/rls-canonicalize.ts +7 -0
- package/src/exports/runtime.ts +1 -0
- package/src/exports/schema-ir-annotations.ts +1 -0
- package/src/exports/sql-utils.ts +1 -0
- package/src/exports/types.ts +37 -0
- package/dist/codec-ids-BvytN2P8.mjs.map +0 -1
- package/dist/codec-ids-CnXu9Qy3.d.mts.map +0 -1
- package/dist/codec-types-DHCkwPKE.d.mts.map +0 -1
- package/dist/codecs--0A5_4Bq.d.mts.map +0 -1
- package/dist/ddl-QDyOSeLc.mjs.map +0 -1
- package/dist/default-normalizer-DyyCHQWs.mjs +0 -131
- package/dist/default-normalizer-DyyCHQWs.mjs.map +0 -1
- package/dist/descriptor-meta-CpGygXpI.mjs +0 -140
- package/dist/descriptor-meta-CpGygXpI.mjs.map +0 -1
- package/dist/errors-CUk87ByX.mjs +0 -33
- package/dist/errors-CUk87ByX.mjs.map +0 -1
- package/dist/issue-planner-DL6g3CmE.mjs +0 -824
- package/dist/issue-planner-DL6g3CmE.mjs.map +0 -1
- package/dist/native-type-normalizer-Bc9XJzWC.mjs +0 -38
- package/dist/native-type-normalizer-Bc9XJzWC.mjs.map +0 -1
- package/dist/nodes-Bbhs2rwj.mjs +0 -76
- package/dist/nodes-Bbhs2rwj.mjs.map +0 -1
- package/dist/nodes-pLeLgdis.d.mts +0 -67
- package/dist/nodes-pLeLgdis.d.mts.map +0 -1
- package/dist/op-factory-call-D_p5vxwt.mjs.map +0 -1
- package/dist/op-factory-call-DmQEc3XV.d.mts.map +0 -1
- package/dist/planner-Bs_baQax.mjs +0 -324
- package/dist/planner-Bs_baQax.mjs.map +0 -1
- package/dist/planner-ddl-builders-B2wOwLqI.mjs.map +0 -1
- package/dist/planner-target-details-CIY6tLeo.d.mts.map +0 -1
- package/dist/postgres-contract-serializer-k3TAcPMY.mjs.map +0 -1
- package/dist/postgres-migration-B5jKrXv3.mjs.map +0 -1
- package/dist/postgres-migration-Y4YBJqkS.d.mts.map +0 -1
- package/dist/postgres-schema-COGZ1ark.mjs.map +0 -1
- package/dist/render-typescript-KMgosran.mjs.map +0 -1
- package/dist/types.d.mts.map +0 -1
- package/src/core/postgres-enum-type-schema.ts +0 -17
package/src/core/codecs.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Each codec ships as three artifacts:
|
|
5
5
|
*
|
|
6
6
|
* 1. A `PgXCodec` class extending {@link CodecImpl} that wraps the module-level encode/decode/encodeJson/decodeJson constants exported from `codec-helpers.ts` (the single source of truth for non-trivial runtime conversions; trivial identity passthroughs are inlined). 2. A `PgXDescriptor` class extending {@link CodecDescriptorImpl} declaring the codec id, traits, target types, params schema, meta, and (where applicable)
|
|
7
|
-
* the emit-path `renderOutputType`. 3. A per-codec column helper (`pgXColumn`) that calls `descriptor.factory(...)` directly and packages the result into a
|
|
7
|
+
* the emit-path `renderOutputType`. 3. A per-codec column helper (`pgXColumn`) that calls `descriptor.factory(...)` directly and packages the result into a framework `ColumnSpec` via the framework {@link column} packager. The helper is tied to its descriptor with `satisfies ColumnHelperFor` (and `ColumnHelperForStrict` where the resolved codec type is well-defined).
|
|
8
8
|
*
|
|
9
9
|
* After TML-2357 this is the canonical source of Postgres codec metadata and runtime behaviour — the legacy `mkCodec` / `defineCodec` carriers (and the parallel `byScalar`/`codecDescriptorDefinitions`/ `codecDescriptorList` collection exports) retired with the deletion sweep.
|
|
10
10
|
*
|
|
@@ -19,11 +19,14 @@ import {
|
|
|
19
19
|
CodecDescriptorImpl,
|
|
20
20
|
CodecImpl,
|
|
21
21
|
type CodecInstanceContext,
|
|
22
|
+
type CodecMeta,
|
|
22
23
|
type ColumnHelperFor,
|
|
23
24
|
type ColumnHelperForStrict,
|
|
24
25
|
column,
|
|
26
|
+
renderTsLiteral,
|
|
25
27
|
voidParamsSchema,
|
|
26
28
|
} from '@prisma-next/framework-components/codec';
|
|
29
|
+
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
27
30
|
import {
|
|
28
31
|
SqlCharCodec,
|
|
29
32
|
SqlFloatCodec,
|
|
@@ -59,6 +62,7 @@ import {
|
|
|
59
62
|
PG_BOOL_CODEC_ID,
|
|
60
63
|
PG_BYTEA_CODEC_ID,
|
|
61
64
|
PG_CHAR_CODEC_ID,
|
|
65
|
+
PG_ENUM_CODEC_ID,
|
|
62
66
|
PG_FLOAT_CODEC_ID,
|
|
63
67
|
PG_FLOAT4_CODEC_ID,
|
|
64
68
|
PG_FLOAT8_CODEC_ID,
|
|
@@ -80,6 +84,8 @@ import {
|
|
|
80
84
|
PG_VARBIT_CODEC_ID,
|
|
81
85
|
PG_VARCHAR_CODEC_ID,
|
|
82
86
|
} from './codec-ids';
|
|
87
|
+
import { DEFAULT_NAMESPACE_ID } from './namespace-ids';
|
|
88
|
+
import { PostgresNativeEnum } from './postgres-native-enum';
|
|
83
89
|
|
|
84
90
|
type LengthParams = { readonly length?: number };
|
|
85
91
|
type PrecisionParams = { readonly precision?: number };
|
|
@@ -148,6 +154,9 @@ export class PgTextDescriptor extends CodecDescriptorImpl<void> {
|
|
|
148
154
|
override readonly targetTypes = ['text'] as const;
|
|
149
155
|
override readonly meta = PG_TEXT_META;
|
|
150
156
|
override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
|
|
157
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
158
|
+
return renderTsLiteral(value);
|
|
159
|
+
}
|
|
151
160
|
override factory(): (ctx: CodecInstanceContext) => PgTextCodec {
|
|
152
161
|
return () => new PgTextCodec(this);
|
|
153
162
|
}
|
|
@@ -161,6 +170,145 @@ export const pgTextColumn = () =>
|
|
|
161
170
|
pgTextColumn satisfies ColumnHelperFor<PgTextDescriptor>;
|
|
162
171
|
pgTextColumn satisfies ColumnHelperForStrict<PgTextDescriptor>;
|
|
163
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Codec for a `pg.enum(Ref)` column bound to a native Postgres enum type.
|
|
175
|
+
* Text passthrough, identical to `pg/text@1` — encode/decode do not carry the
|
|
176
|
+
* enum's member values; membership is enforced by the native type itself, not
|
|
177
|
+
* by this codec. `renderValueLiteral` renders a member value as its TS
|
|
178
|
+
* literal, which is what drives the column's typed value-union (via
|
|
179
|
+
* `renderValueSetType` reading the column's `valueSet` ref) — the codec
|
|
180
|
+
* itself carries no params of its own; typing comes entirely from the
|
|
181
|
+
* column's value-set, not from `pg/enum@1`.
|
|
182
|
+
*
|
|
183
|
+
* A distinct codec id (rather than reusing `pg/text@1` on a plain text
|
|
184
|
+
* column) keeps native-enum columns independently identifiable — from a
|
|
185
|
+
* column's `codecId` alone, without also inspecting `nativeType` — which
|
|
186
|
+
* the managed (DDL) phase needs to target `CREATE TYPE`/`ALTER TYPE`
|
|
187
|
+
* operations at exactly the columns that use one.
|
|
188
|
+
*/
|
|
189
|
+
export class PgEnumCodec extends CodecImpl<
|
|
190
|
+
typeof PG_ENUM_CODEC_ID,
|
|
191
|
+
readonly ['equality', 'order', 'textual'],
|
|
192
|
+
string,
|
|
193
|
+
string
|
|
194
|
+
> {
|
|
195
|
+
async encode(value: string, _ctx: CodecCallContext): Promise<string> {
|
|
196
|
+
return value;
|
|
197
|
+
}
|
|
198
|
+
async decode(wire: string, _ctx: CodecCallContext): Promise<string> {
|
|
199
|
+
return wire;
|
|
200
|
+
}
|
|
201
|
+
encodeJson(value: string): JsonValue {
|
|
202
|
+
return value;
|
|
203
|
+
}
|
|
204
|
+
decodeJson(json: JsonValue): string {
|
|
205
|
+
return blindCast<
|
|
206
|
+
string,
|
|
207
|
+
'text codec: a native-enum member value is stored as its wire string form'
|
|
208
|
+
>(json);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
type PgEnumParams = { readonly typeName: string };
|
|
213
|
+
|
|
214
|
+
const pgEnumParamsSchema = arktype({
|
|
215
|
+
typeName: 'string',
|
|
216
|
+
}) satisfies StandardSchemaV1<PgEnumParams>;
|
|
217
|
+
|
|
218
|
+
function isJsonObject(
|
|
219
|
+
value: JsonValue | undefined,
|
|
220
|
+
): value is { readonly [key: string]: JsonValue } {
|
|
221
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export class PgEnumDescriptor extends CodecDescriptorImpl<PgEnumParams> {
|
|
225
|
+
override readonly codecId = PG_ENUM_CODEC_ID;
|
|
226
|
+
override readonly traits = ['equality', 'order', 'textual'] as const;
|
|
227
|
+
override readonly targetTypes = ['text'] as const;
|
|
228
|
+
override readonly meta = PG_TEXT_META;
|
|
229
|
+
override readonly paramsSchema = pgEnumParamsSchema satisfies StandardSchemaV1<PgEnumParams>;
|
|
230
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
231
|
+
return renderTsLiteral(value);
|
|
232
|
+
}
|
|
233
|
+
override metaFor(typeParams: JsonValue | undefined): CodecMeta | undefined {
|
|
234
|
+
if (!isJsonObject(typeParams)) return this.meta;
|
|
235
|
+
const typeName = typeParams['typeName'];
|
|
236
|
+
return typeof typeName === 'string'
|
|
237
|
+
? { db: { sql: { postgres: { nativeType: typeName } } } }
|
|
238
|
+
: this.meta;
|
|
239
|
+
}
|
|
240
|
+
override factory(_params: PgEnumParams): (ctx: CodecInstanceContext) => PgEnumCodec {
|
|
241
|
+
return () => new PgEnumCodec(this);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Authoring-time hook a `pg.enum(<ref>)` type constructor calls once it has
|
|
246
|
+
* resolved its ref argument to the referenced `native_enum` entity:
|
|
247
|
+
* produces this codec's per-column `typeParams` and native type from the
|
|
248
|
+
* entity's bare type name. Schema-qualification (`auth.aal_level` for a
|
|
249
|
+
* named non-default schema) is not this hook's concern — the field's
|
|
250
|
+
* namespace isn't known at this call site for every authoring path (the TS
|
|
251
|
+
* builder resolves a column before it knows its model's namespace), so it is
|
|
252
|
+
* applied later, at contract construction, by {@link qualifyNativeType} via
|
|
253
|
+
* the target's `authoring.qualifyColumnType` hook. `nativeType` mirrors
|
|
254
|
+
* `typeParams.typeName` — the same value {@link metaFor} derives at render
|
|
255
|
+
* time — so the column's declared native type and the render-time cast
|
|
256
|
+
* agree. Returns `undefined` if `entity` is not a `PostgresNativeEnum` (a
|
|
257
|
+
* contributor bug, not a user-schema error — the caller decides how to
|
|
258
|
+
* report it).
|
|
259
|
+
*/
|
|
260
|
+
columnFromEntity(
|
|
261
|
+
entity: object,
|
|
262
|
+
): { readonly typeParams: PgEnumParams; readonly nativeType: string } | undefined {
|
|
263
|
+
if (!PostgresNativeEnum.is(entity)) return undefined;
|
|
264
|
+
return { typeParams: { typeName: entity.typeName }, nativeType: entity.typeName };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Schema-qualifies this native enum type's name for the namespace the
|
|
269
|
+
* consuming column lives in: `${namespaceId}.${typeName}` for a named
|
|
270
|
+
* non-default schema, bare for the target's default schema (`public`) or
|
|
271
|
+
* the late-bound unbound sentinel (whose schema `search_path` resolves at
|
|
272
|
+
* runtime). Postgres's `format_type()` reports the bare name for a
|
|
273
|
+
* public-schema type, so a public column's declared native type must stay
|
|
274
|
+
* bare to match. Owned here because the codec owns its native type.
|
|
275
|
+
*/
|
|
276
|
+
qualifyNativeType(typeName: string, namespaceId: string): string {
|
|
277
|
+
return namespaceId === DEFAULT_NAMESPACE_ID || namespaceId === UNBOUND_NAMESPACE_ID
|
|
278
|
+
? typeName
|
|
279
|
+
: `${namespaceId}.${typeName}`;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export const pgEnumDescriptor = new PgEnumDescriptor();
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Contract-construction-time column-type qualifier the Postgres target
|
|
287
|
+
* contributes through `authoring.qualifyColumnType`.
|
|
288
|
+
* `buildSqlContractFromDefinition` calls this for every column as it is
|
|
289
|
+
* constructed, passing the column's bare type info and its owning
|
|
290
|
+
* `namespaceId`; a native-enum column (`pg/enum@1`) gets its type name
|
|
291
|
+
* schema-qualified for that namespace (via
|
|
292
|
+
* {@link PgEnumDescriptor.qualifyNativeType}), keeping `nativeType` and
|
|
293
|
+
* `typeParams.typeName` in sync. Every other codec passes through unchanged.
|
|
294
|
+
* Both the PSL `pg.enum(Ref)` path and the TS `pg.enum(handle)` path route
|
|
295
|
+
* through here — the dispatch keys off the codec id, not authoring surface.
|
|
296
|
+
*/
|
|
297
|
+
export function postgresQualifyColumnType(
|
|
298
|
+
input: {
|
|
299
|
+
readonly codecId: string;
|
|
300
|
+
readonly nativeType: string;
|
|
301
|
+
readonly typeParams?: Record<string, unknown>;
|
|
302
|
+
},
|
|
303
|
+
namespaceId: string,
|
|
304
|
+
): { readonly nativeType: string; readonly typeParams?: Record<string, unknown> } {
|
|
305
|
+
if (input.codecId !== PG_ENUM_CODEC_ID) return input;
|
|
306
|
+
const bareTypeName = input.typeParams?.['typeName'];
|
|
307
|
+
if (typeof bareTypeName !== 'string') return input;
|
|
308
|
+
const qualified = pgEnumDescriptor.qualifyNativeType(bareTypeName, namespaceId);
|
|
309
|
+
return { nativeType: qualified, typeParams: { ...input.typeParams, typeName: qualified } };
|
|
310
|
+
}
|
|
311
|
+
|
|
164
312
|
/**
|
|
165
313
|
* Postgres `text[]` codec. Encode is an identity pass-through: the pg wire
|
|
166
314
|
* driver serialises a JS `string[]` to a Postgres array literal under the
|
|
@@ -228,6 +376,9 @@ export class PgInt4Descriptor extends CodecDescriptorImpl<void> {
|
|
|
228
376
|
override readonly targetTypes = ['int4'] as const;
|
|
229
377
|
override readonly meta = PG_INT4_META;
|
|
230
378
|
override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
|
|
379
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
380
|
+
return renderTsLiteral(value);
|
|
381
|
+
}
|
|
231
382
|
override factory(): (ctx: CodecInstanceContext) => PgInt4Codec {
|
|
232
383
|
return () => new PgInt4Codec(this);
|
|
233
384
|
}
|
|
@@ -267,6 +418,9 @@ export class PgInt2Descriptor extends CodecDescriptorImpl<void> {
|
|
|
267
418
|
override readonly targetTypes = ['int2'] as const;
|
|
268
419
|
override readonly meta = PG_INT2_META;
|
|
269
420
|
override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
|
|
421
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
422
|
+
return renderTsLiteral(value);
|
|
423
|
+
}
|
|
270
424
|
override factory(): (ctx: CodecInstanceContext) => PgInt2Codec {
|
|
271
425
|
return () => new PgInt2Codec(this);
|
|
272
426
|
}
|
|
@@ -306,6 +460,9 @@ export class PgInt8Descriptor extends CodecDescriptorImpl<void> {
|
|
|
306
460
|
override readonly targetTypes = ['int8'] as const;
|
|
307
461
|
override readonly meta = PG_INT8_META;
|
|
308
462
|
override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
|
|
463
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
464
|
+
return renderTsLiteral(value);
|
|
465
|
+
}
|
|
309
466
|
override factory(): (ctx: CodecInstanceContext) => PgInt8Codec {
|
|
310
467
|
return () => new PgInt8Codec(this);
|
|
311
468
|
}
|
|
@@ -345,6 +502,9 @@ export class PgFloat4Descriptor extends CodecDescriptorImpl<void> {
|
|
|
345
502
|
override readonly targetTypes = ['float4'] as const;
|
|
346
503
|
override readonly meta = PG_FLOAT4_META;
|
|
347
504
|
override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
|
|
505
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
506
|
+
return renderTsLiteral(value);
|
|
507
|
+
}
|
|
348
508
|
override factory(): (ctx: CodecInstanceContext) => PgFloat4Codec {
|
|
349
509
|
return () => new PgFloat4Codec(this);
|
|
350
510
|
}
|
|
@@ -384,6 +544,9 @@ export class PgFloat8Descriptor extends CodecDescriptorImpl<void> {
|
|
|
384
544
|
override readonly targetTypes = ['float8'] as const;
|
|
385
545
|
override readonly meta = PG_FLOAT8_META;
|
|
386
546
|
override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
|
|
547
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
548
|
+
return renderTsLiteral(value);
|
|
549
|
+
}
|
|
387
550
|
override factory(): (ctx: CodecInstanceContext) => PgFloat8Codec {
|
|
388
551
|
return () => new PgFloat8Codec(this);
|
|
389
552
|
}
|
|
@@ -423,6 +586,9 @@ export class PgBoolDescriptor extends CodecDescriptorImpl<void> {
|
|
|
423
586
|
override readonly targetTypes = ['bool'] as const;
|
|
424
587
|
override readonly meta = PG_BOOL_META;
|
|
425
588
|
override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
|
|
589
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
590
|
+
return renderTsLiteral(value);
|
|
591
|
+
}
|
|
426
592
|
override factory(): (ctx: CodecInstanceContext) => PgBoolCodec {
|
|
427
593
|
return () => new PgBoolCodec(this);
|
|
428
594
|
}
|
|
@@ -968,6 +1134,9 @@ export class PgCharDescriptor extends CodecDescriptorImpl<LengthParams> {
|
|
|
968
1134
|
override renderOutputType(params: LengthParams): string | undefined {
|
|
969
1135
|
return sqlCharDescriptor.renderOutputType(params);
|
|
970
1136
|
}
|
|
1137
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
1138
|
+
return renderTsLiteral(value);
|
|
1139
|
+
}
|
|
971
1140
|
override factory(_params: LengthParams): (ctx: CodecInstanceContext) => SqlCharCodec {
|
|
972
1141
|
return () => new SqlCharCodec(this);
|
|
973
1142
|
}
|
|
@@ -989,6 +1158,9 @@ export class PgVarcharDescriptor extends CodecDescriptorImpl<LengthParams> {
|
|
|
989
1158
|
override renderOutputType(params: LengthParams): string | undefined {
|
|
990
1159
|
return sqlVarcharDescriptor.renderOutputType(params);
|
|
991
1160
|
}
|
|
1161
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
1162
|
+
return renderTsLiteral(value);
|
|
1163
|
+
}
|
|
992
1164
|
override factory(_params: LengthParams): (ctx: CodecInstanceContext) => SqlVarcharCodec {
|
|
993
1165
|
return () => new SqlVarcharCodec(this);
|
|
994
1166
|
}
|
|
@@ -1012,6 +1184,9 @@ export class PgIntDescriptor extends CodecDescriptorImpl<void> {
|
|
|
1012
1184
|
override readonly meta = PG_INT_META;
|
|
1013
1185
|
override readonly traits = sqlIntDescriptor.traits;
|
|
1014
1186
|
override readonly paramsSchema = sqlIntDescriptor.paramsSchema;
|
|
1187
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
1188
|
+
return renderTsLiteral(value);
|
|
1189
|
+
}
|
|
1015
1190
|
override factory(): (ctx: CodecInstanceContext) => SqlIntCodec {
|
|
1016
1191
|
return () => new SqlIntCodec(this);
|
|
1017
1192
|
}
|
|
@@ -1030,6 +1205,9 @@ export class PgFloatDescriptor extends CodecDescriptorImpl<void> {
|
|
|
1030
1205
|
override readonly meta = PG_FLOAT_META;
|
|
1031
1206
|
override readonly traits = sqlFloatDescriptor.traits;
|
|
1032
1207
|
override readonly paramsSchema = sqlFloatDescriptor.paramsSchema;
|
|
1208
|
+
override renderValueLiteral(value: JsonValue): string | undefined {
|
|
1209
|
+
return renderTsLiteral(value);
|
|
1210
|
+
}
|
|
1033
1211
|
override factory(): (ctx: CodecInstanceContext) => SqlFloatCodec {
|
|
1034
1212
|
return () => new SqlFloatCodec(this);
|
|
1035
1213
|
}
|
|
@@ -1052,6 +1230,7 @@ export const codecDescriptors: readonly AnyCodecDescriptor[] = [
|
|
|
1052
1230
|
sqlTextDescriptor,
|
|
1053
1231
|
sqlTimestampDescriptor,
|
|
1054
1232
|
pgTextDescriptor,
|
|
1233
|
+
pgEnumDescriptor,
|
|
1055
1234
|
pgCharDescriptor,
|
|
1056
1235
|
pgVarcharDescriptor,
|
|
1057
1236
|
pgIntDescriptor,
|
package/src/core/ddl/nodes.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
DdlNode,
|
|
4
4
|
type DdlTableConstraint,
|
|
5
5
|
} from '@prisma-next/sql-relational-core/ast';
|
|
6
|
+
import type { RlsPolicyOperation } from '../rls/canonicalize';
|
|
6
7
|
|
|
7
8
|
// ---------------------------------------------------------------------------
|
|
8
9
|
// AlterTableAction — nested polymorphic hierarchy
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
|
|
11
12
|
export interface AlterTableActionVisitor<R> {
|
|
12
13
|
addColumn(action: AddColumnAction): R;
|
|
14
|
+
dropDefault(action: DropDefaultAction): R;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export abstract class AlterTableAction {
|
|
@@ -32,7 +34,31 @@ export class AddColumnAction extends AlterTableAction {
|
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
export
|
|
37
|
+
export class DropDefaultAction extends AlterTableAction {
|
|
38
|
+
readonly kind = 'drop-default' as const;
|
|
39
|
+
readonly columnName: string;
|
|
40
|
+
|
|
41
|
+
constructor(columnName: string) {
|
|
42
|
+
super();
|
|
43
|
+
this.columnName = columnName;
|
|
44
|
+
Object.freeze(this);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override accept<R>(visitor: AlterTableActionVisitor<R>): R {
|
|
48
|
+
return visitor.dropDefault(this);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The set of ALTER TABLE subactions currently expressible as typed DDL.
|
|
54
|
+
*
|
|
55
|
+
* The remaining actions — SetDefault, SetNotNull, DropNotNull,
|
|
56
|
+
* AlterColumnType — are still emitted as raw SQL by `operations/columns.ts`
|
|
57
|
+
* and join this union as they are converted to typed DDL. Until then it is
|
|
58
|
+
* intentionally partial: only the ALTER subactions used by the
|
|
59
|
+
* already-converted ops (AddColumn, DropDefault) appear here.
|
|
60
|
+
*/
|
|
61
|
+
export type AnyAlterTableAction = AddColumnAction | DropDefaultAction;
|
|
36
62
|
|
|
37
63
|
// ---------------------------------------------------------------------------
|
|
38
64
|
// Top-level DDL visitor
|
|
@@ -41,7 +67,13 @@ export type AnyAlterTableAction = AddColumnAction;
|
|
|
41
67
|
export interface PostgresDdlVisitor<R> {
|
|
42
68
|
createTable(node: PostgresCreateTable): R;
|
|
43
69
|
createSchema(node: PostgresCreateSchema): R;
|
|
70
|
+
createType(node: PostgresCreateType): R;
|
|
71
|
+
dropType(node: PostgresDropType): R;
|
|
44
72
|
alterTable(node: PostgresAlterTable): R;
|
|
73
|
+
createPolicy(node: PostgresCreatePolicy): R;
|
|
74
|
+
dropPolicy(node: PostgresDropPolicy): R;
|
|
75
|
+
alterPolicyRename(node: PostgresAlterPolicyRename): R;
|
|
76
|
+
disableRowLevelSecurity(node: PostgresDisableRowLevelSecurity): R;
|
|
45
77
|
}
|
|
46
78
|
|
|
47
79
|
export abstract class PostgresDdlNode extends DdlNode {
|
|
@@ -104,6 +136,46 @@ export class PostgresCreateSchema extends PostgresDdlNode {
|
|
|
104
136
|
}
|
|
105
137
|
}
|
|
106
138
|
|
|
139
|
+
export class PostgresCreateType extends PostgresDdlNode {
|
|
140
|
+
readonly kind = 'create-type' as const;
|
|
141
|
+
readonly schema: string | undefined;
|
|
142
|
+
readonly name: string;
|
|
143
|
+
readonly values: ReadonlyArray<string>;
|
|
144
|
+
|
|
145
|
+
constructor(options: {
|
|
146
|
+
readonly schema?: string;
|
|
147
|
+
readonly name: string;
|
|
148
|
+
readonly values: readonly string[];
|
|
149
|
+
}) {
|
|
150
|
+
super();
|
|
151
|
+
this.schema = options.schema;
|
|
152
|
+
this.name = options.name;
|
|
153
|
+
this.values = Object.freeze([...options.values]);
|
|
154
|
+
this.freeze();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
override accept<R>(visitor: PostgresDdlVisitor<R>): R {
|
|
158
|
+
return visitor.createType(this);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export class PostgresDropType extends PostgresDdlNode {
|
|
163
|
+
readonly kind = 'drop-type' as const;
|
|
164
|
+
readonly schema: string | undefined;
|
|
165
|
+
readonly name: string;
|
|
166
|
+
|
|
167
|
+
constructor(options: { readonly schema?: string; readonly name: string }) {
|
|
168
|
+
super();
|
|
169
|
+
this.schema = options.schema;
|
|
170
|
+
this.name = options.name;
|
|
171
|
+
this.freeze();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
override accept<R>(visitor: PostgresDdlVisitor<R>): R {
|
|
175
|
+
return visitor.dropType(this);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
107
179
|
export class PostgresAlterTable extends PostgresDdlNode {
|
|
108
180
|
readonly kind = 'alter-table' as const;
|
|
109
181
|
readonly table: string;
|
|
@@ -127,4 +199,115 @@ export class PostgresAlterTable extends PostgresDdlNode {
|
|
|
127
199
|
}
|
|
128
200
|
}
|
|
129
201
|
|
|
130
|
-
export type
|
|
202
|
+
export type { RlsPolicyOperation };
|
|
203
|
+
|
|
204
|
+
export class PostgresCreatePolicy extends PostgresDdlNode {
|
|
205
|
+
readonly kind = 'create-policy' as const;
|
|
206
|
+
readonly schema: string;
|
|
207
|
+
readonly table: string;
|
|
208
|
+
readonly name: string;
|
|
209
|
+
readonly permissive: boolean;
|
|
210
|
+
readonly operation: RlsPolicyOperation;
|
|
211
|
+
readonly roles: ReadonlyArray<string>;
|
|
212
|
+
readonly using: string | undefined;
|
|
213
|
+
readonly withCheck: string | undefined;
|
|
214
|
+
|
|
215
|
+
constructor(options: {
|
|
216
|
+
readonly schema: string;
|
|
217
|
+
readonly table: string;
|
|
218
|
+
readonly name: string;
|
|
219
|
+
readonly permissive: boolean;
|
|
220
|
+
readonly operation: RlsPolicyOperation;
|
|
221
|
+
readonly roles: readonly string[];
|
|
222
|
+
readonly using?: string;
|
|
223
|
+
readonly withCheck?: string;
|
|
224
|
+
}) {
|
|
225
|
+
super();
|
|
226
|
+
this.schema = options.schema;
|
|
227
|
+
this.table = options.table;
|
|
228
|
+
this.name = options.name;
|
|
229
|
+
this.permissive = options.permissive;
|
|
230
|
+
this.operation = options.operation;
|
|
231
|
+
this.roles = Object.freeze([...options.roles]);
|
|
232
|
+
this.using = options.using;
|
|
233
|
+
this.withCheck = options.withCheck;
|
|
234
|
+
this.freeze();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
override accept<R>(visitor: PostgresDdlVisitor<R>): R {
|
|
238
|
+
return visitor.createPolicy(this);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export class PostgresDropPolicy extends PostgresDdlNode {
|
|
243
|
+
readonly kind = 'drop-policy' as const;
|
|
244
|
+
readonly schema: string;
|
|
245
|
+
readonly table: string;
|
|
246
|
+
readonly name: string;
|
|
247
|
+
|
|
248
|
+
constructor(options: { readonly schema: string; readonly table: string; readonly name: string }) {
|
|
249
|
+
super();
|
|
250
|
+
this.schema = options.schema;
|
|
251
|
+
this.table = options.table;
|
|
252
|
+
this.name = options.name;
|
|
253
|
+
this.freeze();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
override accept<R>(visitor: PostgresDdlVisitor<R>): R {
|
|
257
|
+
return visitor.dropPolicy(this);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export class PostgresAlterPolicyRename extends PostgresDdlNode {
|
|
262
|
+
readonly kind = 'alter-policy-rename' as const;
|
|
263
|
+
readonly schema: string;
|
|
264
|
+
readonly table: string;
|
|
265
|
+
readonly name: string;
|
|
266
|
+
readonly newName: string;
|
|
267
|
+
|
|
268
|
+
constructor(options: {
|
|
269
|
+
readonly schema: string;
|
|
270
|
+
readonly table: string;
|
|
271
|
+
readonly name: string;
|
|
272
|
+
readonly newName: string;
|
|
273
|
+
}) {
|
|
274
|
+
super();
|
|
275
|
+
this.schema = options.schema;
|
|
276
|
+
this.table = options.table;
|
|
277
|
+
this.name = options.name;
|
|
278
|
+
this.newName = options.newName;
|
|
279
|
+
this.freeze();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
override accept<R>(visitor: PostgresDdlVisitor<R>): R {
|
|
283
|
+
return visitor.alterPolicyRename(this);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export class PostgresDisableRowLevelSecurity extends PostgresDdlNode {
|
|
288
|
+
readonly kind = 'disable-row-level-security' as const;
|
|
289
|
+
readonly schema: string;
|
|
290
|
+
readonly table: string;
|
|
291
|
+
|
|
292
|
+
constructor(options: { readonly schema: string; readonly table: string }) {
|
|
293
|
+
super();
|
|
294
|
+
this.schema = options.schema;
|
|
295
|
+
this.table = options.table;
|
|
296
|
+
this.freeze();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
override accept<R>(visitor: PostgresDdlVisitor<R>): R {
|
|
300
|
+
return visitor.disableRowLevelSecurity(this);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export type AnyPostgresDdlNode =
|
|
305
|
+
| PostgresCreateTable
|
|
306
|
+
| PostgresCreateSchema
|
|
307
|
+
| PostgresCreateType
|
|
308
|
+
| PostgresDropType
|
|
309
|
+
| PostgresAlterTable
|
|
310
|
+
| PostgresCreatePolicy
|
|
311
|
+
| PostgresDropPolicy
|
|
312
|
+
| PostgresAlterPolicyRename
|
|
313
|
+
| PostgresDisableRowLevelSecurity;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ColumnDefault } from '@prisma-next/contract/types';
|
|
1
|
+
import type { ColumnDefault, JsonValue } from '@prisma-next/contract/types';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Pre-compiled regex patterns for performance.
|
|
@@ -18,6 +18,13 @@ const FALSE_PATTERN = /^false$/i;
|
|
|
18
18
|
const NUMERIC_PATTERN = /^-?\d+(\.\d+)?$/;
|
|
19
19
|
const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:"[^"]+"|[\w\s]+)(?:\(\d+\))?)?$/;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Matches a Postgres array literal default of the form `'{...}'::elemtype[]`.
|
|
23
|
+
* The literal body is captured in group 1; the cast (including `[]`) is optional.
|
|
24
|
+
* Examples: `'{}'::text[]`, `'{1,2}'::integer[]`, `'{}'`
|
|
25
|
+
*/
|
|
26
|
+
const ARRAY_LITERAL_PATTERN = /^'(\{.*\})'(?:::.+\[\])?$/;
|
|
27
|
+
|
|
21
28
|
/**
|
|
22
29
|
* Returns the canonical expression for a timestamp default function, or undefined
|
|
23
30
|
* if the expression is not a recognized timestamp default.
|
|
@@ -51,6 +58,108 @@ function canonicalizeTimestampDefault(expr: string): string | undefined {
|
|
|
51
58
|
return undefined;
|
|
52
59
|
}
|
|
53
60
|
|
|
61
|
+
type ArrayElementToken = { readonly value: string; readonly quoted: boolean };
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Splits a Postgres array literal body (without the enclosing braces) into its
|
|
65
|
+
* element tokens, honouring quoting. A comma only separates elements when it is
|
|
66
|
+
* outside double quotes; inside a quoted element a doubled quote (`""`) or a
|
|
67
|
+
* backslash-escaped quote (`\"`) is a literal quote, and a backslash escapes the
|
|
68
|
+
* next character. Returns undefined if the body is malformed (e.g. an unbalanced
|
|
69
|
+
* quote).
|
|
70
|
+
*/
|
|
71
|
+
function splitArrayElements(inner: string): readonly ArrayElementToken[] | undefined {
|
|
72
|
+
const tokens: ArrayElementToken[] = [];
|
|
73
|
+
let current = '';
|
|
74
|
+
let inQuotes = false;
|
|
75
|
+
let quoted = false;
|
|
76
|
+
|
|
77
|
+
for (let i = 0; i < inner.length; i++) {
|
|
78
|
+
const char = inner[i];
|
|
79
|
+
if (inQuotes) {
|
|
80
|
+
if (char === '\\') {
|
|
81
|
+
const next = inner[i + 1];
|
|
82
|
+
if (next === undefined) return undefined;
|
|
83
|
+
current += next;
|
|
84
|
+
i++;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (char === '"') {
|
|
88
|
+
if (inner[i + 1] === '"') {
|
|
89
|
+
current += '"';
|
|
90
|
+
i++;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
inQuotes = false;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
current += char;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (char === '"') {
|
|
100
|
+
inQuotes = true;
|
|
101
|
+
quoted = true;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (char === ',') {
|
|
105
|
+
tokens.push({ value: current, quoted });
|
|
106
|
+
current = '';
|
|
107
|
+
quoted = false;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
current += char;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (inQuotes) return undefined;
|
|
114
|
+
tokens.push({ value: current, quoted });
|
|
115
|
+
return tokens;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Parses a Postgres array literal body (`{...}`) into a JS array of primitives.
|
|
120
|
+
* Returns undefined if the body cannot be reliably parsed.
|
|
121
|
+
*
|
|
122
|
+
* Handles:
|
|
123
|
+
* - `{}` → `[]`
|
|
124
|
+
* - `{elem1,elem2,...}` → `[elem1, elem2, ...]` with numeric and string element coercion
|
|
125
|
+
* - quoted elements that contain commas, doubled/escaped quotes, and the literal
|
|
126
|
+
* strings `NULL`/`true`/`false` (a quoted token is always a string)
|
|
127
|
+
*/
|
|
128
|
+
function parseArrayLiteralBody(body: string): readonly JsonValue[] | undefined {
|
|
129
|
+
const inner = body.slice(1, -1).trim();
|
|
130
|
+
if (inner === '') return [];
|
|
131
|
+
const tokens = splitArrayElements(inner);
|
|
132
|
+
if (tokens === undefined) return undefined;
|
|
133
|
+
const result: JsonValue[] = [];
|
|
134
|
+
for (const token of tokens) {
|
|
135
|
+
if (token.quoted) {
|
|
136
|
+
// A quoted token is always a string — `"NULL"`, `"true"`, `"1"` are the
|
|
137
|
+
// literal text, never the keyword/number.
|
|
138
|
+
result.push(token.value);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const el = token.value.trim();
|
|
142
|
+
if (el.toUpperCase() === 'NULL') {
|
|
143
|
+
result.push(null);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (el === 'true') {
|
|
147
|
+
result.push(true);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (el === 'false') {
|
|
151
|
+
result.push(false);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (NUMERIC_PATTERN.test(el)) {
|
|
155
|
+
result.push(Number(el));
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
|
|
54
163
|
/**
|
|
55
164
|
* Parses a raw Postgres column default expression into a normalized ColumnDefault.
|
|
56
165
|
* This enables semantic comparison between contract defaults and introspected schema defaults.
|
|
@@ -59,7 +168,7 @@ function canonicalizeTimestampDefault(expr: string): string | undefined {
|
|
|
59
168
|
* keeping the introspection layer focused on faithful data capture.
|
|
60
169
|
*
|
|
61
170
|
* @param rawDefault - Raw default expression from information_schema.columns.column_default
|
|
62
|
-
* @param nativeType - Native column type, used for type-aware parsing (bigint
|
|
171
|
+
* @param nativeType - Native column type, used for type-aware parsing (array, bigint, JSON)
|
|
63
172
|
* @returns Normalized ColumnDefault or undefined if the expression cannot be parsed
|
|
64
173
|
*/
|
|
65
174
|
export function parsePostgresDefault(
|
|
@@ -69,11 +178,22 @@ export function parsePostgresDefault(
|
|
|
69
178
|
const trimmed = rawDefault.trim();
|
|
70
179
|
const normalizedType = nativeType?.toLowerCase();
|
|
71
180
|
const isBigInt = normalizedType === 'bigint' || normalizedType === 'int8';
|
|
181
|
+
const isArrayType = normalizedType?.endsWith('[]') ?? false;
|
|
72
182
|
|
|
73
183
|
if (NEXTVAL_PATTERN.test(trimmed)) {
|
|
74
184
|
return { kind: 'function', expression: 'autoincrement()' };
|
|
75
185
|
}
|
|
76
186
|
|
|
187
|
+
if (isArrayType) {
|
|
188
|
+
const arrayMatch = trimmed.match(ARRAY_LITERAL_PATTERN);
|
|
189
|
+
if (arrayMatch?.[1] !== undefined) {
|
|
190
|
+
const parsed = parseArrayLiteralBody(arrayMatch[1]);
|
|
191
|
+
if (parsed !== undefined) {
|
|
192
|
+
return { kind: 'literal', value: parsed };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
77
197
|
const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);
|
|
78
198
|
if (canonicalTimestamp) {
|
|
79
199
|
return { kind: 'function', expression: canonicalTimestamp };
|