@prisma-next/target-postgres 0.15.0 → 0.16.0-dev.10
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-BtsOWgI3.mjs → authoring-34L18kA1.mjs} +18 -8
- package/dist/authoring-34L18kA1.mjs.map +1 -0
- package/dist/canonicalize-D1F4vUnP.d.mts.map +1 -1
- package/dist/{codec-ids-CI144z7g.d.mts → codec-ids-BswpvvND.d.mts} +3 -3
- package/dist/codec-ids-BswpvvND.d.mts.map +1 -0
- package/dist/{codec-ids-B10ZZHzw.mjs → codec-ids-D3G8K0YM.mjs} +3 -2
- package/dist/codec-ids-D3G8K0YM.mjs.map +1 -0
- package/dist/codec-ids.d.mts +2 -2
- package/dist/codec-ids.mjs +2 -2
- package/dist/{codec-types-CTfT4U4O.d.mts → codec-types-CQ07nOz-.d.mts} +4 -5
- package/dist/codec-types-CQ07nOz-.d.mts.map +1 -0
- package/dist/codec-types.d.mts +1 -1
- package/dist/{codecs-D7W9O0Xx.d.mts → codecs-G4DTY0F_.d.mts} +35 -7
- package/dist/codecs-G4DTY0F_.d.mts.map +1 -0
- package/dist/{codecs-DRbb26Or.mjs → codecs-TCsGgW-Y.mjs} +77 -5
- package/dist/codecs-TCsGgW-Y.mjs.map +1 -0
- package/dist/codecs.d.mts +2 -3
- package/dist/codecs.d.mts.map +1 -1
- package/dist/codecs.mjs +2 -2
- package/dist/contract-free.d.mts +2 -3
- package/dist/contract-free.d.mts.map +1 -1
- package/dist/contract-free.mjs +3 -3
- package/dist/{control-policy-DtbkLLGv.mjs → control-policy-S7XBe07W.mjs} +44 -75
- package/dist/control-policy-S7XBe07W.mjs.map +1 -0
- package/dist/control.d.mts +0 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +75 -25
- package/dist/control.mjs.map +1 -1
- package/dist/data-transform-BOWpliq8.mjs.map +1 -1
- package/dist/{data-transform-DPzwBMhW.d.mts → data-transform-CGvE8yGx.d.mts} +1 -2
- package/dist/data-transform-CGvE8yGx.d.mts.map +1 -0
- package/dist/data-transform.d.mts +1 -1
- package/dist/{ddl-GTTOvjx_.mjs → ddl-DHXKzQ99.mjs} +3 -3
- package/dist/{ddl-GTTOvjx_.mjs.map → ddl-DHXKzQ99.mjs.map} +1 -1
- package/dist/ddl.d.mts +1 -1
- package/dist/default-normalizer-B9ZUiyUE.mjs +264 -0
- package/dist/default-normalizer-B9ZUiyUE.mjs.map +1 -0
- package/dist/default-normalizer.d.mts +14 -2
- package/dist/default-normalizer.d.mts.map +1 -1
- package/dist/default-normalizer.mjs +2 -248
- package/dist/{descriptor-meta-CFQKLXl_.mjs → descriptor-meta-qubYaxQA.mjs} +9 -4
- package/dist/descriptor-meta-qubYaxQA.mjs.map +1 -0
- package/dist/{diff-database-schema-GncqMuSI.mjs → diff-database-schema-BRxq7l98.mjs} +92 -26
- package/dist/diff-database-schema-BRxq7l98.mjs.map +1 -0
- package/dist/diff-database-schema.d.mts +4 -13
- package/dist/diff-database-schema.d.mts.map +1 -1
- package/dist/diff-database-schema.mjs +1 -1
- package/dist/{errors-DO-w0EUS.mjs → errors-ByDS0xJL.mjs} +6 -6
- package/dist/errors-ByDS0xJL.mjs.map +1 -0
- package/dist/errors.d.mts +4 -4
- package/dist/errors.d.mts.map +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/issue-planner.d.mts +1 -2
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.d.mts +3 -4
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +2 -2
- package/dist/native-type-normalizer.d.mts.map +1 -1
- package/dist/{nodes-Dv5eCSq9.d.mts → nodes-CQzM2hR0.d.mts} +1 -2
- package/dist/nodes-CQzM2hR0.d.mts.map +1 -0
- package/dist/{op-factory-call-C38NzvQD.mjs → op-factory-call-Ci3H6InB.mjs} +37 -21
- package/dist/op-factory-call-Ci3H6InB.mjs.map +1 -0
- package/dist/{op-factory-call-Bn9zDx4_.d.mts → op-factory-call-DT7kdjVP.d.mts} +10 -7
- package/dist/op-factory-call-DT7kdjVP.d.mts.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 +122 -6
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/{planner-kql24i_F.mjs → planner-BpL7uktH.mjs} +15 -15
- package/dist/planner-BpL7uktH.mjs.map +1 -0
- package/dist/planner-ddl-builders.d.mts +1 -2
- package/dist/planner-ddl-builders.d.mts.map +1 -1
- package/dist/planner-identity-values.d.mts +0 -1
- package/dist/planner-identity-values.d.mts.map +1 -1
- package/dist/{planner-produced-postgres-migration-BEY1T0Xm.d.mts → planner-produced-postgres-migration-8QP8eMph.d.mts} +3 -4
- package/dist/planner-produced-postgres-migration-8QP8eMph.d.mts.map +1 -0
- package/dist/{planner-produced-postgres-migration-D7y-PEHK.mjs → planner-produced-postgres-migration-D8exrrxA.mjs} +8 -5
- package/dist/planner-produced-postgres-migration-D8exrrxA.mjs.map +1 -0
- package/dist/planner-produced-postgres-migration.d.mts +1 -1
- package/dist/planner-produced-postgres-migration.mjs +1 -1
- package/dist/planner-schema-lookup.d.mts +0 -1
- package/dist/planner-schema-lookup.d.mts.map +1 -1
- package/dist/{planner-sql-checks-zqNfs2XZ.mjs → planner-sql-checks-BuB877wH.mjs} +2 -2
- package/dist/{planner-sql-checks-zqNfs2XZ.mjs.map → planner-sql-checks-BuB877wH.mjs.map} +1 -1
- package/dist/planner-sql-checks.d.mts +0 -1
- package/dist/planner-sql-checks.d.mts.map +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/planner-target-details-HkP4RrRO.d.mts.map +1 -1
- package/dist/planner.d.mts +9 -4
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +2 -2
- package/dist/{postgres-contract-view-C9j5cqP0.d.mts → postgres-contract-view-CeU7FJjW.d.mts} +4 -3
- package/dist/postgres-contract-view-CeU7FJjW.d.mts.map +1 -0
- package/dist/{postgres-contract-view-DM8sN1Ot.mjs → postgres-contract-view-DebHMqGR.mjs} +4 -4
- package/dist/{postgres-contract-view-DM8sN1Ot.mjs.map → postgres-contract-view-DebHMqGR.mjs.map} +1 -1
- package/dist/{postgres-database-schema-node-CJv5bfbs.d.mts → postgres-database-schema-node-DMXsIwAb.d.mts} +12 -4
- package/dist/postgres-database-schema-node-DMXsIwAb.d.mts.map +1 -0
- package/dist/{postgres-migration-arMSWU9b.mjs → postgres-migration-Bn3fj1I4.mjs} +22 -6
- package/dist/postgres-migration-Bn3fj1I4.mjs.map +1 -0
- package/dist/{postgres-migration-DbckK1su.d.mts → postgres-migration-DLIvzHjX.d.mts} +31 -7
- package/dist/postgres-migration-DLIvzHjX.d.mts.map +1 -0
- package/dist/{postgres-rls-policy--CSddvMR.d.mts → postgres-rls-policy-CYXdqG9B.d.mts} +1 -2
- package/dist/postgres-rls-policy-CYXdqG9B.d.mts.map +1 -0
- package/dist/{postgres-role-schema-node-Cm-j0ZGM.mjs → postgres-role-schema-node-bg32e7I-.mjs} +3 -2
- package/dist/postgres-role-schema-node-bg32e7I-.mjs.map +1 -0
- package/dist/{postgres-schema-Cm4DtiGA.mjs → postgres-schema-CewLYHB7.mjs} +2 -2
- package/dist/{postgres-schema-Cm4DtiGA.mjs.map → postgres-schema-CewLYHB7.mjs.map} +1 -1
- package/dist/{postgres-schema-DKq6s1P3.d.mts → postgres-schema-FdKRwe7X.d.mts} +3 -4
- package/dist/postgres-schema-FdKRwe7X.d.mts.map +1 -0
- package/dist/render-ops.d.mts +0 -1
- package/dist/render-ops.d.mts.map +1 -1
- package/dist/{render-typescript-7yqILcwr.mjs → render-typescript-Ta7_6CGf.mjs} +20 -8
- package/dist/render-typescript-Ta7_6CGf.mjs.map +1 -0
- package/dist/render-typescript.d.mts +2 -1
- package/dist/render-typescript.d.mts.map +1 -1
- package/dist/render-typescript.mjs +1 -1
- package/dist/{resolve-ddl-schema-XyBaaenM.mjs → resolve-ddl-schema-D0wi_P9Q.mjs} +2 -2
- package/dist/{resolve-ddl-schema-XyBaaenM.mjs.map → resolve-ddl-schema-D0wi_P9Q.mjs.map} +1 -1
- package/dist/rls-canonicalize.d.mts +0 -1
- package/dist/rls-canonicalize.d.mts.map +1 -1
- package/dist/runtime.d.mts +1 -2
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/schema-ir-annotations.d.mts +0 -1
- package/dist/schema-ir-annotations.d.mts.map +1 -1
- package/dist/schema-ir-annotations.mjs +1 -1
- package/dist/schema-node-kinds-DxvWh2Ic.d.mts +29 -0
- package/dist/schema-node-kinds-DxvWh2Ic.d.mts.map +1 -0
- package/dist/sql-utils.d.mts.map +1 -1
- package/dist/{table-source-BvFo7gVs.d.mts → table-source-D5c2fxAQ.d.mts} +1 -2
- package/dist/table-source-D5c2fxAQ.d.mts.map +1 -0
- package/dist/{types-BDKkx8MA.d.mts → types-D2MLzLBD.d.mts} +1 -2
- package/dist/types-D2MLzLBD.d.mts.map +1 -0
- package/dist/types.d.mts +6 -5
- package/dist/types.mjs +4 -4
- package/package.json +21 -21
- package/src/core/authoring.ts +18 -5
- package/src/core/codec-helpers.ts +53 -1
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codecs.ts +56 -3
- package/src/core/default-normalizer.ts +22 -0
- package/src/core/descriptor-meta.ts +2 -0
- package/src/core/errors.ts +5 -5
- package/src/core/index-types.ts +15 -0
- package/src/core/migrations/contract-to-postgres-database-schema-node.ts +99 -19
- package/src/core/migrations/control-policy.ts +4 -3
- package/src/core/migrations/diff-database-schema.ts +6 -3
- package/src/core/migrations/issue-planner.ts +41 -80
- package/src/core/migrations/op-factory-call.ts +41 -22
- package/src/core/migrations/operations/data-transform.ts +2 -2
- package/src/core/migrations/planner-produced-postgres-migration.ts +9 -2
- package/src/core/migrations/planner-strategies.ts +6 -6
- package/src/core/migrations/planner.ts +13 -4
- package/src/core/migrations/postgres-migration.ts +62 -2
- package/src/core/migrations/render-typescript.ts +20 -8
- package/src/core/migrations/runner.ts +12 -11
- package/src/core/migrations/verify-postgres-namespaces.ts +0 -1
- package/src/core/psl-infer/infer-psl-contract.ts +130 -12
- package/src/core/schema-ir/postgres-policy-schema-node.ts +12 -2
- package/src/exports/codecs.ts +2 -0
- package/src/exports/control.ts +2 -0
- package/src/exports/default-normalizer.ts +1 -1
- package/src/exports/op-factory-call.ts +5 -0
- package/src/exports/types.ts +1 -0
- package/dist/authoring-BtsOWgI3.mjs.map +0 -1
- package/dist/codec-ids-B10ZZHzw.mjs.map +0 -1
- package/dist/codec-ids-CI144z7g.d.mts.map +0 -1
- package/dist/codec-types-CTfT4U4O.d.mts.map +0 -1
- package/dist/codecs-D7W9O0Xx.d.mts.map +0 -1
- package/dist/codecs-DRbb26Or.mjs.map +0 -1
- package/dist/control-policy-DtbkLLGv.mjs.map +0 -1
- package/dist/data-transform-DPzwBMhW.d.mts.map +0 -1
- package/dist/default-normalizer.mjs.map +0 -1
- package/dist/descriptor-meta-CFQKLXl_.mjs.map +0 -1
- package/dist/diff-database-schema-GncqMuSI.mjs.map +0 -1
- package/dist/errors-DO-w0EUS.mjs.map +0 -1
- package/dist/nodes-Dv5eCSq9.d.mts.map +0 -1
- package/dist/op-factory-call-Bn9zDx4_.d.mts.map +0 -1
- package/dist/op-factory-call-C38NzvQD.mjs.map +0 -1
- package/dist/planner-kql24i_F.mjs.map +0 -1
- package/dist/planner-produced-postgres-migration-BEY1T0Xm.d.mts.map +0 -1
- package/dist/planner-produced-postgres-migration-D7y-PEHK.mjs.map +0 -1
- package/dist/postgres-contract-view-C9j5cqP0.d.mts.map +0 -1
- package/dist/postgres-database-schema-node-CJv5bfbs.d.mts.map +0 -1
- package/dist/postgres-migration-DbckK1su.d.mts.map +0 -1
- package/dist/postgres-migration-arMSWU9b.mjs.map +0 -1
- package/dist/postgres-rls-policy--CSddvMR.d.mts.map +0 -1
- package/dist/postgres-role-schema-node-Cm-j0ZGM.mjs.map +0 -1
- package/dist/postgres-schema-DKq6s1P3.d.mts.map +0 -1
- package/dist/render-typescript-7yqILcwr.mjs.map +0 -1
- package/dist/table-source-BvFo7gVs.d.mts.map +0 -1
- package/dist/types-BDKkx8MA.d.mts.map +0 -1
|
@@ -47,7 +47,7 @@ export const pgNumericDecode = (wire: string | number): string => {
|
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
export const pgNumericRenderOutputType = (typeParams: {
|
|
50
|
-
readonly precision
|
|
50
|
+
readonly precision?: number;
|
|
51
51
|
readonly scale?: number;
|
|
52
52
|
}): string | undefined => {
|
|
53
53
|
const precision = typeParams.precision;
|
|
@@ -106,6 +106,58 @@ export const pgTimestamptzDecodeJson = (json: JsonValue): Date => {
|
|
|
106
106
|
return date;
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
+
const ISO_8601_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
110
|
+
|
|
111
|
+
function formatDateOnly(year: number, month: number, day: number): string {
|
|
112
|
+
return `${String(year).padStart(4, '0')}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* A Postgres `date` has no time-of-day or timezone component, so `pg/date@1`
|
|
117
|
+
* canonicalizes its JS-level value as a `Date` at UTC midnight
|
|
118
|
+
* (`Date.UTC(y, m, d)`), independent of the process's local timezone.
|
|
119
|
+
*
|
|
120
|
+
* `pgDateEncode` reads the calendar date via UTC getters (matching that
|
|
121
|
+
* canonical form) and formats it as `YYYY-MM-DD` directly, bypassing the pg
|
|
122
|
+
* driver's own `Date` serialization (`dateToString`), which reads *local*
|
|
123
|
+
* getters and would shift the calendar day near midnight in negative-UTC-offset
|
|
124
|
+
* environments.
|
|
125
|
+
*/
|
|
126
|
+
export const pgDateEncode = (value: Date): string =>
|
|
127
|
+
formatDateOnly(value.getUTCFullYear(), value.getUTCMonth() + 1, value.getUTCDate());
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Normalizes the pg driver's already-parsed `Date` for a `date` column into
|
|
131
|
+
* the canonical UTC-midnight form. The driver (via `postgres-date`) builds
|
|
132
|
+
* that `Date` at *local* midnight from the wire text; reading it back with the
|
|
133
|
+
* same (local) getters recovers the exact calendar date the driver parsed,
|
|
134
|
+
* and reconstructing via `Date.UTC` makes the result's instant independent of
|
|
135
|
+
* the process's timezone.
|
|
136
|
+
*/
|
|
137
|
+
export const pgDateDecode = (wire: Date): Date =>
|
|
138
|
+
new Date(Date.UTC(wire.getFullYear(), wire.getMonth(), wire.getDate()));
|
|
139
|
+
|
|
140
|
+
export const pgDateEncodeJson = (value: Date): JsonValue => pgDateEncode(value);
|
|
141
|
+
|
|
142
|
+
export const pgDateDecodeJson = (json: JsonValue): Date => {
|
|
143
|
+
if (typeof json !== 'string') {
|
|
144
|
+
throw new Error(`Expected date string for pg/date@1, got ${typeof json}`);
|
|
145
|
+
}
|
|
146
|
+
const match = ISO_8601_DATE.exec(json);
|
|
147
|
+
if (!match) {
|
|
148
|
+
throw new Error(`Invalid date string for pg/date@1: ${json}`);
|
|
149
|
+
}
|
|
150
|
+
const [, yearText, monthText, dayText] = match;
|
|
151
|
+
const year = Number(yearText);
|
|
152
|
+
const month = Number(monthText) - 1;
|
|
153
|
+
const day = Number(dayText);
|
|
154
|
+
const date = new Date(Date.UTC(year, month, day));
|
|
155
|
+
if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month || date.getUTCDate() !== day) {
|
|
156
|
+
throw new Error(`Invalid date string for pg/date@1: ${json}`);
|
|
157
|
+
}
|
|
158
|
+
return date;
|
|
159
|
+
};
|
|
160
|
+
|
|
109
161
|
export const pgIntervalDecode = (wire: string | Record<string, unknown>): string => {
|
|
110
162
|
if (typeof wire === 'string') return wire;
|
|
111
163
|
return JSON.stringify(wire);
|
package/src/core/codec-ids.ts
CHANGED
|
@@ -22,6 +22,7 @@ export const PG_NUMERIC_CODEC_ID = 'pg/numeric@1' as const;
|
|
|
22
22
|
export const PG_BOOL_CODEC_ID = 'pg/bool@1' as const;
|
|
23
23
|
export const PG_BIT_CODEC_ID = 'pg/bit@1' as const;
|
|
24
24
|
export const PG_VARBIT_CODEC_ID = 'pg/varbit@1' as const;
|
|
25
|
+
export const PG_DATE_CODEC_ID = 'pg/date@1' as const;
|
|
25
26
|
export const PG_TIMESTAMP_CODEC_ID = 'pg/timestamp@1' as const;
|
|
26
27
|
export const PG_TIMESTAMPTZ_CODEC_ID = 'pg/timestamptz@1' as const;
|
|
27
28
|
export const PG_TIME_CODEC_ID = 'pg/time@1' as const;
|
package/src/core/codecs.ts
CHANGED
|
@@ -45,6 +45,10 @@ import { type as arktype } from 'arktype';
|
|
|
45
45
|
import {
|
|
46
46
|
pgByteaDecodeJson,
|
|
47
47
|
pgByteaEncodeJson,
|
|
48
|
+
pgDateDecode,
|
|
49
|
+
pgDateDecodeJson,
|
|
50
|
+
pgDateEncode,
|
|
51
|
+
pgDateEncodeJson,
|
|
48
52
|
pgIntervalDecode,
|
|
49
53
|
pgJsonbDecode,
|
|
50
54
|
pgJsonbEncode,
|
|
@@ -64,6 +68,7 @@ import {
|
|
|
64
68
|
PG_BOOL_CODEC_ID,
|
|
65
69
|
PG_BYTEA_CODEC_ID,
|
|
66
70
|
PG_CHAR_CODEC_ID,
|
|
71
|
+
PG_DATE_CODEC_ID,
|
|
67
72
|
PG_ENUM_CODEC_ID,
|
|
68
73
|
PG_FLOAT_CODEC_ID,
|
|
69
74
|
PG_FLOAT4_CODEC_ID,
|
|
@@ -92,14 +97,14 @@ import { PostgresNativeEnum } from './postgres-native-enum';
|
|
|
92
97
|
|
|
93
98
|
type LengthParams = { readonly length?: number };
|
|
94
99
|
type PrecisionParams = { readonly precision?: number };
|
|
95
|
-
type NumericParams = { readonly precision
|
|
100
|
+
type NumericParams = { readonly precision?: number; readonly scale?: number };
|
|
96
101
|
|
|
97
102
|
const lengthParamsSchema = arktype({
|
|
98
103
|
'length?': 'number.integer > 0',
|
|
99
104
|
}) satisfies StandardSchemaV1<LengthParams>;
|
|
100
105
|
|
|
101
106
|
const numericParamsSchema = arktype({
|
|
102
|
-
precision: 'number.integer > 0 & number.integer <= 1000',
|
|
107
|
+
'precision?': 'number.integer > 0 & number.integer <= 1000',
|
|
103
108
|
'scale?': 'number.integer >= 0',
|
|
104
109
|
}) satisfies StandardSchemaV1<NumericParams>;
|
|
105
110
|
|
|
@@ -115,6 +120,7 @@ const PG_INT8_META = { db: { sql: { postgres: { nativeType: 'bigint' } } } } as
|
|
|
115
120
|
const PG_FLOAT4_META = { db: { sql: { postgres: { nativeType: 'real' } } } } as const;
|
|
116
121
|
const PG_FLOAT8_META = { db: { sql: { postgres: { nativeType: 'double precision' } } } } as const;
|
|
117
122
|
const PG_NUMERIC_META = { db: { sql: { postgres: { nativeType: 'numeric' } } } } as const;
|
|
123
|
+
const PG_DATE_META = { db: { sql: { postgres: { nativeType: 'date' } } } } as const;
|
|
118
124
|
const PG_TIMESTAMP_META = {
|
|
119
125
|
db: { sql: { postgres: { nativeType: 'timestamp without time zone' } } },
|
|
120
126
|
} as const;
|
|
@@ -648,12 +654,57 @@ export class PgNumericDescriptor extends CodecDescriptorImpl<NumericParams> {
|
|
|
648
654
|
|
|
649
655
|
export const pgNumericDescriptor = new PgNumericDescriptor();
|
|
650
656
|
|
|
651
|
-
export const pgNumericColumn = (params: NumericParams) =>
|
|
657
|
+
export const pgNumericColumn = (params: NumericParams = {}) =>
|
|
652
658
|
column(pgNumericDescriptor.factory(params), pgNumericDescriptor.codecId, params, 'numeric');
|
|
653
659
|
|
|
654
660
|
pgNumericColumn satisfies ColumnHelperFor<PgNumericDescriptor>;
|
|
655
661
|
pgNumericColumn satisfies ColumnHelperForStrict<PgNumericDescriptor>;
|
|
656
662
|
|
|
663
|
+
/**
|
|
664
|
+
* A Postgres `date` has no time-of-day or timezone component. This codec
|
|
665
|
+
* canonicalizes its JS-level value as a `Date` at UTC midnight, so its
|
|
666
|
+
* round-trip is independent of the process's local timezone — see
|
|
667
|
+
* `pgDateEncode`/`pgDateDecode` in `codec-helpers.ts`.
|
|
668
|
+
*/
|
|
669
|
+
export class PgDateCodec extends CodecImpl<
|
|
670
|
+
typeof PG_DATE_CODEC_ID,
|
|
671
|
+
readonly ['equality', 'order'],
|
|
672
|
+
Date | string,
|
|
673
|
+
Date
|
|
674
|
+
> {
|
|
675
|
+
async encode(value: Date, _ctx: CodecCallContext): Promise<string> {
|
|
676
|
+
return pgDateEncode(value);
|
|
677
|
+
}
|
|
678
|
+
async decode(wire: Date, _ctx: CodecCallContext): Promise<Date> {
|
|
679
|
+
return pgDateDecode(wire);
|
|
680
|
+
}
|
|
681
|
+
encodeJson(value: Date): JsonValue {
|
|
682
|
+
return pgDateEncodeJson(value);
|
|
683
|
+
}
|
|
684
|
+
decodeJson(json: JsonValue): Date {
|
|
685
|
+
return pgDateDecodeJson(json);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
export class PgDateDescriptor extends CodecDescriptorImpl<void> {
|
|
690
|
+
override readonly codecId = PG_DATE_CODEC_ID;
|
|
691
|
+
override readonly traits = ['equality', 'order'] as const;
|
|
692
|
+
override readonly targetTypes = ['date'] as const;
|
|
693
|
+
override readonly meta = PG_DATE_META;
|
|
694
|
+
override readonly paramsSchema: StandardSchemaV1<void> = voidParamsSchema;
|
|
695
|
+
override factory(): (ctx: CodecInstanceContext) => PgDateCodec {
|
|
696
|
+
return () => new PgDateCodec(this);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
export const pgDateDescriptor = new PgDateDescriptor();
|
|
701
|
+
|
|
702
|
+
export const pgDateColumn = () =>
|
|
703
|
+
column(pgDateDescriptor.factory(), pgDateDescriptor.codecId, undefined, 'date');
|
|
704
|
+
|
|
705
|
+
pgDateColumn satisfies ColumnHelperFor<PgDateDescriptor>;
|
|
706
|
+
pgDateColumn satisfies ColumnHelperForStrict<PgDateDescriptor>;
|
|
707
|
+
|
|
657
708
|
export class PgTimestampCodec extends CodecImpl<
|
|
658
709
|
typeof PG_TIMESTAMP_CODEC_ID,
|
|
659
710
|
readonly ['equality', 'order'],
|
|
@@ -1285,6 +1336,8 @@ export const codecDescriptors: readonly AnyCodecDescriptor[] = [
|
|
|
1285
1336
|
pgFloat4Descriptor,
|
|
1286
1337
|
pgFloat8Descriptor,
|
|
1287
1338
|
pgNumericDescriptor,
|
|
1339
|
+
// PSL `@db.Date` binding is deferred to remove-db-attributes' `Date` type; pin it via codecId, not a second targetTypes activation here.
|
|
1340
|
+
pgDateDescriptor,
|
|
1288
1341
|
pgTimestampDescriptor,
|
|
1289
1342
|
pgTimestamptzDescriptor,
|
|
1290
1343
|
pgTimeDescriptor,
|
|
@@ -249,3 +249,25 @@ export function parsePostgresDefault(
|
|
|
249
249
|
|
|
250
250
|
return { kind: 'function', expression: trimmed };
|
|
251
251
|
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Normalizes a contract-declared default through {@link parsePostgresDefault}
|
|
255
|
+
* — the same parser introspection uses — so a function-shaped default the
|
|
256
|
+
* parser recognizes as a literal (e.g. `dbgenerated("'{}'::jsonb")`)
|
|
257
|
+
* resolves to the same `resolvedDefault` shape a live introspected column
|
|
258
|
+
* would produce. Compensates once, at `SchemaIR` construction of the
|
|
259
|
+
* expected (contract-derived) side (`contractToSchemaIR`'s `resolveDefault`
|
|
260
|
+
* hook), instead of at every site that later compares the two sides. A
|
|
261
|
+
* literal default, or a function form the parser doesn't recognize, passes
|
|
262
|
+
* through unchanged; `nextval(...)` normalizes to `autoincrement()` on both
|
|
263
|
+
* sides, matching a `serial`/identity column's introspected counterpart.
|
|
264
|
+
*/
|
|
265
|
+
export function postgresResolveDefault(
|
|
266
|
+
def: ColumnDefault,
|
|
267
|
+
resolvedNativeType: string,
|
|
268
|
+
): ColumnDefault {
|
|
269
|
+
if (def.kind !== 'function') {
|
|
270
|
+
return def;
|
|
271
|
+
}
|
|
272
|
+
return parsePostgresDefault(def.expression, resolvedNativeType) ?? def;
|
|
273
|
+
}
|
|
@@ -9,12 +9,14 @@ import {
|
|
|
9
9
|
} from './authoring';
|
|
10
10
|
import { postgresQualifyColumnType } from './codecs';
|
|
11
11
|
import { postgresTargetDescriptorMetaRuntime } from './descriptor-meta-runtime';
|
|
12
|
+
import { postgresIndexTypes } from './index-types';
|
|
12
13
|
import { DEFAULT_NAMESPACE_ID } from './namespace-ids';
|
|
13
14
|
import { postgresCreateNamespace } from './postgres-schema';
|
|
14
15
|
|
|
15
16
|
const postgresTargetDescriptorMetaBase = {
|
|
16
17
|
...postgresTargetDescriptorMetaRuntime,
|
|
17
18
|
defaultNamespaceId: DEFAULT_NAMESPACE_ID,
|
|
19
|
+
indexTypes: postgresIndexTypes,
|
|
18
20
|
authoring: {
|
|
19
21
|
type: postgresAuthoringTypes,
|
|
20
22
|
field: postgresAuthoringFieldPresets,
|
package/src/core/errors.ts
CHANGED
|
@@ -12,9 +12,10 @@ import { CliStructuredError } from '@prisma-next/errors/control';
|
|
|
12
12
|
* The `operation` argument is required so every throw site names the operation
|
|
13
13
|
* that actually failed; a new operation cannot inherit a misattributed message.
|
|
14
14
|
*
|
|
15
|
-
* Distinct from `
|
|
16
|
-
* (data-transform query
|
|
17
|
-
*
|
|
15
|
+
* Distinct from `MIGRATION.UNFILLED_PLACEHOLDER` (placeholder not filled)
|
|
16
|
+
* and `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH` (data-transform query
|
|
17
|
+
* plan against wrong contract) because the missing input is the stack
|
|
18
|
+
* itself, not the per-operation contract.
|
|
18
19
|
*
|
|
19
20
|
* Lives in `@prisma-next/target-postgres/errors` rather than the shared
|
|
20
21
|
* framework migration errors module because the failure is target-specific:
|
|
@@ -23,10 +24,9 @@ import { CliStructuredError } from '@prisma-next/errors/control';
|
|
|
23
24
|
*/
|
|
24
25
|
export function errorPostgresMigrationStackMissing(operation: string): CliStructuredError {
|
|
25
26
|
return new CliStructuredError(
|
|
26
|
-
'
|
|
27
|
+
'MIGRATION.POSTGRES_CONTROL_STACK_MISSING',
|
|
27
28
|
`PostgresMigration.${operation} requires a control adapter`,
|
|
28
29
|
{
|
|
29
|
-
domain: 'MIG',
|
|
30
30
|
why: `PostgresMigration.${operation} was invoked on an instance constructed without a ControlStack, so the stored controlAdapter is undefined and the operation cannot lower its plan.`,
|
|
31
31
|
fix: 'Construct the migration via the migration CLI entrypoint (which assembles a ControlStack from the loaded prisma-next.config.ts), or pass a ControlStack containing a Postgres adapter to the migration constructor in test fixtures.',
|
|
32
32
|
meta: { operation },
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineIndexTypes } from '@prisma-next/sql-contract/index-types';
|
|
2
|
+
import { type } from 'arktype';
|
|
3
|
+
|
|
4
|
+
// Postgres's built-in index access methods (`CREATE INDEX ... USING <method>`).
|
|
5
|
+
// Per-method option validation (e.g. `gin` operator classes) is out of scope;
|
|
6
|
+
// every method accepts any options object until a later slice narrows it.
|
|
7
|
+
export const postgresIndexTypes = defineIndexTypes()
|
|
8
|
+
.add('btree', { options: type('object') })
|
|
9
|
+
.add('hash', { options: type('object') })
|
|
10
|
+
.add('gin', { options: type('object') })
|
|
11
|
+
.add('gist', { options: type('object') })
|
|
12
|
+
.add('spgist', { options: type('object') })
|
|
13
|
+
.add('brin', { options: type('object') });
|
|
14
|
+
|
|
15
|
+
export type IndexTypes = typeof postgresIndexTypes.IndexTypes;
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { ContractToSchemaIROptions } from '@prisma-next/family-sql/control';
|
|
2
2
|
import { contractNamespaceToSchemaIR } from '@prisma-next/family-sql/control';
|
|
3
|
+
import type { SchemaNodeRef } from '@prisma-next/framework-components/control';
|
|
3
4
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
PrimaryKey,
|
|
7
|
+
RelationalSchemaNodeKind,
|
|
8
|
+
SqlForeignKeyIR,
|
|
9
|
+
SqlIndexIR,
|
|
10
|
+
SqlUniqueIR,
|
|
11
|
+
} from '@prisma-next/sql-schema-ir/types';
|
|
5
12
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
6
13
|
import type { PostgresRlsPolicy } from '../postgres-rls-policy';
|
|
7
14
|
import type { PostgresContract } from '../postgres-schema';
|
|
@@ -12,8 +19,43 @@ import { PostgresNativeEnumSchemaNode } from '../schema-ir/postgres-native-enum-
|
|
|
12
19
|
import { PostgresPolicySchemaNode } from '../schema-ir/postgres-policy-schema-node';
|
|
13
20
|
import { PostgresRoleSchemaNode } from '../schema-ir/postgres-role-schema-node';
|
|
14
21
|
import { PostgresTableSchemaNode } from '../schema-ir/postgres-table-schema-node';
|
|
22
|
+
import { PostgresSchemaNodeKind } from '../schema-ir/schema-node-kinds';
|
|
15
23
|
import { resolveDdlSchemaForNamespaceStorage } from './resolve-ddl-schema';
|
|
16
24
|
|
|
25
|
+
/** The database root's fixed sentinel id (`PostgresDatabaseSchemaNode#id`). */
|
|
26
|
+
function databaseStep(): { readonly nodeKind: string; readonly id: string } {
|
|
27
|
+
return { nodeKind: PostgresSchemaNodeKind.database, id: 'database' };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function tableDependsOn(namespaceId: string, tableName: string): SchemaNodeRef {
|
|
31
|
+
return [
|
|
32
|
+
databaseStep(),
|
|
33
|
+
{ nodeKind: PostgresSchemaNodeKind.namespace, id: namespaceId },
|
|
34
|
+
{ nodeKind: PostgresSchemaNodeKind.table, id: tableName },
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function roleDependsOn(role: string): SchemaNodeRef {
|
|
39
|
+
return [databaseStep(), { nodeKind: PostgresSchemaNodeKind.role, id: role }];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The chains from a table-child object (foreign key, index, unique, primary
|
|
44
|
+
* key) to each of the own columns it is built on, in the Postgres tree.
|
|
45
|
+
* Dropping a covered column auto-drops the object, so the object's drop must
|
|
46
|
+
* precede the column's; the graph derives that direction from these edges.
|
|
47
|
+
*/
|
|
48
|
+
function columnDependsOn(
|
|
49
|
+
namespaceId: string,
|
|
50
|
+
tableName: string,
|
|
51
|
+
columns: readonly string[],
|
|
52
|
+
): readonly SchemaNodeRef[] {
|
|
53
|
+
return columns.map((column) => [
|
|
54
|
+
...tableDependsOn(namespaceId, tableName),
|
|
55
|
+
{ nodeKind: RelationalSchemaNodeKind.column, id: `column:${column}` },
|
|
56
|
+
]);
|
|
57
|
+
}
|
|
58
|
+
|
|
17
59
|
function toPolicyNode(policy: PostgresRlsPolicy, namespaceId: string): PostgresPolicySchemaNode {
|
|
18
60
|
return new PostgresPolicySchemaNode({
|
|
19
61
|
name: policy.name,
|
|
@@ -25,6 +67,7 @@ function toPolicyNode(policy: PostgresRlsPolicy, namespaceId: string): PostgresP
|
|
|
25
67
|
...ifDefined('using', policy.using),
|
|
26
68
|
...ifDefined('withCheck', policy.withCheck),
|
|
27
69
|
permissive: policy.permissive,
|
|
70
|
+
dependsOn: [tableDependsOn(namespaceId, policy.tableName), ...policy.roles.map(roleDependsOn)],
|
|
28
71
|
});
|
|
29
72
|
}
|
|
30
73
|
|
|
@@ -115,30 +158,67 @@ export function contractToPostgresDatabaseSchemaNode(
|
|
|
115
158
|
// clauses, and resolves the real live DDL schema — introspected FKs
|
|
116
159
|
// already carry the live schema, so this is what lets an expected FK
|
|
117
160
|
// pair (by diff-node id) with its introspected counterpart.
|
|
118
|
-
const foreignKeys = sqlTable.foreignKeys.map(
|
|
119
|
-
(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
161
|
+
const foreignKeys = sqlTable.foreignKeys.map((fk) => {
|
|
162
|
+
const resolvedReferencedNamespace = resolveDdlSchemaForNamespaceStorage(
|
|
163
|
+
contract.storage,
|
|
164
|
+
fk.referencedSchema ?? UNBOUND_NAMESPACE_ID,
|
|
165
|
+
);
|
|
166
|
+
return new SqlForeignKeyIR({
|
|
167
|
+
columns: fk.columns,
|
|
168
|
+
referencedTable: fk.referencedTable,
|
|
169
|
+
referencedColumns: fk.referencedColumns,
|
|
170
|
+
referencedSchema: fk.referencedSchema ?? UNBOUND_NAMESPACE_ID,
|
|
171
|
+
...ifDefined('name', fk.name),
|
|
172
|
+
...ifDefined('onDelete', fk.onDelete),
|
|
173
|
+
...ifDefined('onUpdate', fk.onUpdate),
|
|
174
|
+
...ifDefined('annotations', fk.annotations),
|
|
175
|
+
resolvedReferencedNamespace,
|
|
176
|
+
dependsOn: [
|
|
177
|
+
tableDependsOn(resolvedReferencedNamespace, fk.referencedTable),
|
|
178
|
+
...columnDependsOn(ddlSchema, tableName, fk.columns),
|
|
179
|
+
],
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
// The family stamped these children's own-column `dependsOn` with the
|
|
183
|
+
// flat (single-schema) chain; the Postgres tree nests them under a
|
|
184
|
+
// namespace, so re-stamp with the multi-schema chain that matches this
|
|
185
|
+
// tree's paths. Every other field is carried through unchanged.
|
|
186
|
+
const uniques = sqlTable.uniques.map(
|
|
187
|
+
(u) =>
|
|
188
|
+
new SqlUniqueIR({
|
|
189
|
+
columns: u.columns,
|
|
190
|
+
...ifDefined('name', u.name),
|
|
191
|
+
...ifDefined('annotations', u.annotations),
|
|
192
|
+
dependsOn: columnDependsOn(ddlSchema, tableName, u.columns),
|
|
193
|
+
}),
|
|
194
|
+
);
|
|
195
|
+
const indexes = sqlTable.indexes.map(
|
|
196
|
+
(i) =>
|
|
197
|
+
new SqlIndexIR({
|
|
198
|
+
columns: i.columns,
|
|
199
|
+
unique: i.unique,
|
|
200
|
+
...ifDefined('name', i.name),
|
|
201
|
+
...ifDefined('type', i.type),
|
|
202
|
+
...ifDefined('options', i.options),
|
|
203
|
+
...ifDefined('annotations', i.annotations),
|
|
204
|
+
dependsOn: columnDependsOn(ddlSchema, tableName, i.columns),
|
|
133
205
|
}),
|
|
134
206
|
);
|
|
207
|
+
const primaryKey =
|
|
208
|
+
sqlTable.primaryKey !== undefined
|
|
209
|
+
? new PrimaryKey({
|
|
210
|
+
columns: sqlTable.primaryKey.columns,
|
|
211
|
+
...ifDefined('name', sqlTable.primaryKey.name),
|
|
212
|
+
dependsOn: columnDependsOn(ddlSchema, tableName, sqlTable.primaryKey.columns),
|
|
213
|
+
})
|
|
214
|
+
: undefined;
|
|
135
215
|
tables[tableName] = new PostgresTableSchemaNode({
|
|
136
216
|
name: sqlTable.name,
|
|
137
217
|
columns: sqlTable.columns,
|
|
138
218
|
foreignKeys,
|
|
139
|
-
uniques
|
|
140
|
-
indexes
|
|
141
|
-
...ifDefined('primaryKey',
|
|
219
|
+
uniques,
|
|
220
|
+
indexes,
|
|
221
|
+
...ifDefined('primaryKey', primaryKey),
|
|
142
222
|
...ifDefined('annotations', sqlTable.annotations),
|
|
143
223
|
...ifDefined('checks', sqlTable.checks),
|
|
144
224
|
policies: policiesByTable.get(tableName) ?? [],
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
SuppressionRecord,
|
|
6
6
|
} from '@prisma-next/family-sql/control';
|
|
7
7
|
import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
8
|
+
import { issueOutcome } from '@prisma-next/framework-components/control';
|
|
8
9
|
import { entityAt, UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
9
10
|
import type { SqlStorage, StorageTable } from '@prisma-next/sql-contract/types';
|
|
10
11
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
@@ -252,7 +253,7 @@ const POSTGRES_NODE_CREATION_FACTORY: Readonly<Record<string, string>> = Object.
|
|
|
252
253
|
* it is not admitted as creation-class here.
|
|
253
254
|
*/
|
|
254
255
|
function isEnablementCreationIssue(issue: SchemaDiffIssue<SqlSchemaDiffNode>): boolean {
|
|
255
|
-
if (issue
|
|
256
|
+
if (issueOutcome(issue) !== 'not-equal') return false;
|
|
256
257
|
const { expected, actual } = issue;
|
|
257
258
|
return (
|
|
258
259
|
expected !== undefined &&
|
|
@@ -270,7 +271,7 @@ export function resolvePostgresNodeIssueCreationFactoryName(
|
|
|
270
271
|
if (isEnablementCreationIssue(issue)) {
|
|
271
272
|
return 'enableRowLevelSecurity';
|
|
272
273
|
}
|
|
273
|
-
if (issue
|
|
274
|
+
if (issueOutcome(issue) !== 'not-found') return undefined;
|
|
274
275
|
const node = issue.expected ?? issue.actual;
|
|
275
276
|
if (node === undefined) return undefined;
|
|
276
277
|
return POSTGRES_NODE_CREATION_FACTORY[node.nodeKind];
|
|
@@ -298,7 +299,7 @@ export function resolvePostgresNodeIssueControlPolicySubject(
|
|
|
298
299
|
>(node);
|
|
299
300
|
return {
|
|
300
301
|
namespaceId: resolveNamespaceIdForDdlSchema(contract, namespaceNode.schemaName),
|
|
301
|
-
createsNewObject: issue
|
|
302
|
+
createsNewObject: issueOutcome(issue) === 'not-found',
|
|
302
303
|
};
|
|
303
304
|
}
|
|
304
305
|
|
|
@@ -4,12 +4,13 @@ import { buildNativeTypeExpander } from '@prisma-next/family-sql/control';
|
|
|
4
4
|
import { classifyDiffSubjectGranularity } from '@prisma-next/family-sql/diff';
|
|
5
5
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
6
6
|
import type { DiffableNode, SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
7
|
-
import { diffSchemas } from '@prisma-next/framework-components/control';
|
|
7
|
+
import { diffSchemas, issueOutcome } from '@prisma-next/framework-components/control';
|
|
8
8
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
9
9
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
10
10
|
import type { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
11
11
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
12
12
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
13
|
+
import { postgresResolveDefault } from '../default-normalizer';
|
|
13
14
|
import type { PostgresContract } from '../postgres-schema';
|
|
14
15
|
import { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
|
|
15
16
|
import { PostgresNamespaceSchemaNode } from '../schema-ir/postgres-namespace-schema-node';
|
|
@@ -135,12 +136,13 @@ export function diffPostgresSchema(input: {
|
|
|
135
136
|
const fullExpected = contractToPostgresDatabaseSchemaNode(postgresContract, {
|
|
136
137
|
annotationNamespace: 'pg',
|
|
137
138
|
...ifDefined('expandNativeType', expandNativeType),
|
|
139
|
+
resolveDefault: postgresResolveDefault,
|
|
138
140
|
});
|
|
139
141
|
const expected = pruneTableLessNamespaces(fullExpected);
|
|
140
142
|
const relationalOwned = ownedSchemaNames(expected);
|
|
141
143
|
const structuralOwned = ownedSchemaNames(fullExpected);
|
|
142
144
|
const issues = diffSchemas(expected, actual).filter((issue) => {
|
|
143
|
-
if (issue
|
|
145
|
+
if (issueOutcome(issue) !== 'not-expected') return true;
|
|
144
146
|
if (isClusterScopedIssue(issue)) return true;
|
|
145
147
|
const granularity = classifyDiffSubjectGranularity(issue, postgresDiffSubjectGranularity);
|
|
146
148
|
const namespaceSegment = issue.path[1];
|
|
@@ -230,6 +232,7 @@ export function buildPostgresPlanDiff(input: {
|
|
|
230
232
|
const projectionOptions = {
|
|
231
233
|
annotationNamespace: 'pg',
|
|
232
234
|
...ifDefined('expandNativeType', expandNativeType),
|
|
235
|
+
resolveDefault: postgresResolveDefault,
|
|
233
236
|
};
|
|
234
237
|
const fullExpected = contractToPostgresDatabaseSchemaNode(postgresContract, projectionOptions);
|
|
235
238
|
const expected = pruneTableLessNamespaces(fullExpected);
|
|
@@ -240,7 +243,7 @@ export function buildPostgresPlanDiff(input: {
|
|
|
240
243
|
readonly SchemaDiffIssue<SqlSchemaDiffNode>[],
|
|
241
244
|
'both trees are PostgresDatabaseSchemaNodes, so every diff-issue node is a SqlSchemaDiffNode'
|
|
242
245
|
>(diffSchemas(expected, paddedActual)).filter((issue) => {
|
|
243
|
-
if (issue
|
|
246
|
+
if (issueOutcome(issue) !== 'not-expected') return true;
|
|
244
247
|
if (isClusterScopedIssue(issue)) return true;
|
|
245
248
|
const granularity = classifyDiffSubjectGranularity(issue, postgresDiffSubjectGranularity);
|
|
246
249
|
const namespaceSegment = issue.path[1];
|