@prisma-next/target-postgres 0.9.0 → 0.10.0
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/{codec-ids-RvYfmUmi.d.mts → codec-ids-D9fJ4HP5.d.mts} +1 -1
- package/dist/{codec-ids-RvYfmUmi.d.mts.map → codec-ids-D9fJ4HP5.d.mts.map} +1 -1
- package/dist/codec-ids.d.mts +1 -1
- package/dist/{codec-types-667FxIW8.d.mts → codec-types-CRlHq7Cz.d.mts} +2 -2
- package/dist/{codec-types-667FxIW8.d.mts.map → codec-types-CRlHq7Cz.d.mts.map} +1 -1
- package/dist/codec-types.d.mts +1 -1
- package/dist/{codecs-DXeDABSO.d.mts → codecs-Dud5KDNk.d.mts} +2 -2
- package/dist/{codecs-DXeDABSO.d.mts.map → codecs-Dud5KDNk.d.mts.map} +1 -1
- package/dist/codecs.d.mts +1 -1
- package/dist/control.d.mts +1 -1
- package/dist/control.mjs +5 -5
- package/dist/{data-transform-COkGR6Ns.mjs → data-transform-CdtGUWp2.mjs} +1 -1
- package/dist/{data-transform-COkGR6Ns.mjs.map → data-transform-CdtGUWp2.mjs.map} +1 -1
- package/dist/{data-transform-B6p02mFJ.d.mts → data-transform-bmOKkygi.d.mts} +2 -2
- package/dist/{data-transform-B6p02mFJ.d.mts.map → data-transform-bmOKkygi.d.mts.map} +1 -1
- package/dist/data-transform.d.mts +1 -1
- package/dist/data-transform.mjs +1 -1
- package/dist/descriptor-meta-zrZzWmJF.mjs +91 -0
- package/dist/{descriptor-meta-DFUCClk_.mjs.map → descriptor-meta-zrZzWmJF.mjs.map} +1 -1
- package/dist/enum-planning.d.mts +1 -1
- package/dist/{errors-BiOloWUh.mjs → errors--zafB5_n.mjs} +1 -1
- package/dist/{errors-BiOloWUh.mjs.map → errors--zafB5_n.mjs.map} +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/{issue-planner-BhWVYyE1.mjs → issue-planner-qalHRCI2.mjs} +179 -77
- package/dist/issue-planner-qalHRCI2.mjs.map +1 -0
- package/dist/issue-planner.d.mts +2 -2
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.d.mts +3 -3
- package/dist/migration.mjs +3 -3
- package/dist/{op-factory-call-c1zELk3U.d.mts → op-factory-call-Drccm_JD.d.mts} +3 -3
- package/dist/{op-factory-call-c1zELk3U.d.mts.map → op-factory-call-Drccm_JD.d.mts.map} +1 -1
- package/dist/{op-factory-call-DerP9BoT.mjs → op-factory-call-Zsrdty3k.mjs} +2 -2
- package/dist/{op-factory-call-DerP9BoT.mjs.map → op-factory-call-Zsrdty3k.mjs.map} +1 -1
- package/dist/op-factory-call.d.mts +1 -1
- package/dist/op-factory-call.mjs +1 -1
- package/dist/pack.d.mts +2 -2
- package/dist/pack.mjs +1 -1
- package/dist/{planner-DnzPpv1j.mjs → planner-C8yhbXOq.mjs} +84 -5
- package/dist/planner-C8yhbXOq.mjs.map +1 -0
- package/dist/{planner-ddl-builders-5QIyhBUF.mjs → planner-ddl-builders-DINYrbJ3.mjs} +4 -4
- package/dist/{planner-ddl-builders-5QIyhBUF.mjs.map → planner-ddl-builders-DINYrbJ3.mjs.map} +1 -1
- package/dist/planner-ddl-builders.d.mts +1 -1
- package/dist/planner-ddl-builders.mjs +1 -1
- package/dist/{planner-identity-values-BUYNOCwb.mjs → planner-identity-values-ojX-6cPV.mjs} +1 -1
- package/dist/{planner-identity-values-BUYNOCwb.mjs.map → planner-identity-values-ojX-6cPV.mjs.map} +1 -1
- package/dist/planner-identity-values.mjs +1 -1
- package/dist/{planner-produced-postgres-migration-FYsKh26I.mjs → planner-produced-postgres-migration-BqGLw7VT.mjs} +4 -4
- package/dist/{planner-produced-postgres-migration-FYsKh26I.mjs.map → planner-produced-postgres-migration-BqGLw7VT.mjs.map} +1 -1
- package/dist/{planner-produced-postgres-migration-D34ftfEK.d.mts → planner-produced-postgres-migration-c9lpjPv1.d.mts} +3 -3
- package/dist/{planner-produced-postgres-migration-D34ftfEK.d.mts.map → planner-produced-postgres-migration-c9lpjPv1.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-schema-lookup-BGyukuzG.mjs +57 -0
- package/dist/planner-schema-lookup-BGyukuzG.mjs.map +1 -0
- package/dist/planner-schema-lookup.d.mts.map +1 -1
- package/dist/planner-schema-lookup.mjs +1 -1
- package/dist/{planner-sql-checks-Cd016Ycs.mjs → planner-sql-checks-BM4sD6Xc.mjs} +28 -11
- package/dist/planner-sql-checks-BM4sD6Xc.mjs.map +1 -0
- package/dist/planner-sql-checks.d.mts +11 -0
- package/dist/planner-sql-checks.d.mts.map +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/{planner-target-details-iYJwzFHP.d.mts → planner-target-details-CIj61DUj.d.mts} +1 -1
- package/dist/{planner-target-details-iYJwzFHP.d.mts.map → planner-target-details-CIj61DUj.d.mts.map} +1 -1
- package/dist/planner-target-details.d.mts +1 -1
- package/dist/planner.d.mts +1 -1
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/postgres-contract-serializer-CcZO9ukP.mjs +83 -0
- package/dist/postgres-contract-serializer-CcZO9ukP.mjs.map +1 -0
- package/dist/{postgres-enum-type-CrKq8au9.d.mts → postgres-enum-type-CNhPTDhy.d.mts} +1 -1
- package/dist/{postgres-enum-type-CrKq8au9.d.mts.map → postgres-enum-type-CNhPTDhy.d.mts.map} +1 -1
- package/dist/{postgres-migration-q4oWyNJE.mjs → postgres-migration-C5os-tkl.mjs} +3 -3
- package/dist/{postgres-migration-q4oWyNJE.mjs.map → postgres-migration-C5os-tkl.mjs.map} +1 -1
- package/dist/{postgres-migration-CiQzhcMe.d.mts → postgres-migration-jvsKgUDM.d.mts} +3 -3
- package/dist/{postgres-migration-CiQzhcMe.d.mts.map → postgres-migration-jvsKgUDM.d.mts.map} +1 -1
- package/dist/postgres-schema-BosNxhWq.mjs +163 -0
- package/dist/postgres-schema-BosNxhWq.mjs.map +1 -0
- package/dist/{render-ops-CkiuHSNj.mjs → render-ops-BC2PtCkj.mjs} +1 -1
- package/dist/{render-ops-CkiuHSNj.mjs.map → render-ops-BC2PtCkj.mjs.map} +1 -1
- package/dist/render-ops.d.mts +1 -1
- package/dist/render-ops.mjs +1 -1
- package/dist/{render-typescript-C9XWI8Ld.mjs → render-typescript-nRHbqLbI.mjs} +1 -1
- package/dist/{render-typescript-C9XWI8Ld.mjs.map → render-typescript-nRHbqLbI.mjs.map} +1 -1
- package/dist/render-typescript.mjs +1 -1
- package/dist/runtime.d.mts +7 -17
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +2 -2
- package/dist/{shared-DLYdmYo-.d.mts → shared-ByhSooBS.d.mts} +6 -4
- package/dist/shared-ByhSooBS.d.mts.map +1 -0
- package/dist/{statement-builders-BSIQMClE.mjs → statement-builders-vImtdfmM.mjs} +1 -1
- package/dist/{statement-builders-BSIQMClE.mjs.map → statement-builders-vImtdfmM.mjs.map} +1 -1
- package/dist/statement-builders.mjs +1 -1
- package/dist/{tables-Ce_Q0I8B.mjs → tables-DZ-5Yxi0.mjs} +3 -3
- package/dist/tables-DZ-5Yxi0.mjs.map +1 -0
- package/dist/{types-Dq74Z3eu.d.mts → types-D-XIpzHA.d.mts} +1 -1
- package/dist/types-D-XIpzHA.d.mts.map +1 -0
- package/dist/types.d.mts +125 -3
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +2 -1
- package/package.json +17 -17
- package/src/core/migrations/issue-planner.ts +131 -41
- package/src/core/migrations/operations/constraints.ts +1 -1
- package/src/core/migrations/operations/shared.ts +4 -2
- package/src/core/migrations/planner-ddl-builders.ts +2 -2
- package/src/core/migrations/planner-schema-lookup.ts +30 -6
- package/src/core/migrations/planner-sql-checks.ts +29 -11
- package/src/core/migrations/planner-strategies.ts +138 -43
- package/src/core/migrations/planner.ts +14 -1
- package/src/core/migrations/verify-postgres-namespaces.ts +87 -0
- package/src/core/postgres-contract-serializer.ts +139 -60
- package/src/core/postgres-schema.ts +208 -0
- package/src/exports/types.ts +5 -0
- package/dist/descriptor-meta-DFUCClk_.mjs +0 -124
- package/dist/issue-planner-BhWVYyE1.mjs.map +0 -1
- package/dist/planner-DnzPpv1j.mjs.map +0 -1
- package/dist/planner-schema-lookup--u9whY_Y.mjs +0 -29
- package/dist/planner-schema-lookup--u9whY_Y.mjs.map +0 -1
- package/dist/planner-sql-checks-Cd016Ycs.mjs.map +0 -1
- package/dist/postgres-contract-serializer-D5VJk6lo.mjs +0 -61
- package/dist/postgres-contract-serializer-D5VJk6lo.mjs.map +0 -1
- package/dist/shared-DLYdmYo-.d.mts.map +0 -1
- package/dist/tables-Ce_Q0I8B.mjs.map +0 -1
- package/dist/types-Dq74Z3eu.d.mts.map +0 -1
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
PostgresEnumStorageEntry,
|
|
23
23
|
SqlStorage,
|
|
24
24
|
StorageColumn,
|
|
25
|
+
StorageTable,
|
|
25
26
|
StorageTypeInstance,
|
|
26
27
|
} from '@prisma-next/sql-contract/types';
|
|
27
28
|
import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
@@ -36,6 +37,7 @@ import {
|
|
|
36
37
|
AlterColumnTypeCall,
|
|
37
38
|
CreateEnumTypeCall,
|
|
38
39
|
CreateIndexCall,
|
|
40
|
+
CreateSchemaCall,
|
|
39
41
|
CreateTableCall,
|
|
40
42
|
DropColumnCall,
|
|
41
43
|
DropConstraintCall,
|
|
@@ -53,17 +55,33 @@ import { buildExpectedFormatType } from './planner-sql-checks';
|
|
|
53
55
|
import {
|
|
54
56
|
type CallMigrationStrategy,
|
|
55
57
|
postgresPlannerStrategies,
|
|
58
|
+
resolveDdlSchemaForNamespace,
|
|
59
|
+
resolveNamespaceIdForIssue,
|
|
56
60
|
type StrategyContext,
|
|
61
|
+
tableAt,
|
|
57
62
|
} from './planner-strategies';
|
|
58
63
|
|
|
59
64
|
export type { CallMigrationStrategy, StrategyContext };
|
|
60
65
|
|
|
66
|
+
function locateNamespaceTypeInStorage(storage: SqlStorage, typeName: string): unknown {
|
|
67
|
+
for (const ns of Object.values(storage.namespaces)) {
|
|
68
|
+
if (!('types' in ns) || ns.types == null) continue;
|
|
69
|
+
const entry = (ns.types as Record<string, unknown>)[typeName];
|
|
70
|
+
if (entry !== undefined) return entry;
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
61
75
|
// ============================================================================
|
|
62
76
|
// Issue kind ordering (dependency order)
|
|
63
77
|
// ============================================================================
|
|
64
78
|
|
|
65
79
|
const ISSUE_KIND_ORDER: Record<string, number> = {
|
|
66
|
-
//
|
|
80
|
+
// Schemas first — the database container must exist before any DDL
|
|
81
|
+
// that targets it can run.
|
|
82
|
+
missing_schema: 1,
|
|
83
|
+
|
|
84
|
+
// Types next
|
|
67
85
|
type_missing: 2,
|
|
68
86
|
type_values_mismatch: 3,
|
|
69
87
|
enum_values_changed: 3,
|
|
@@ -183,22 +201,45 @@ function mapIssueToCall(
|
|
|
183
201
|
ctx: StrategyContext,
|
|
184
202
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
185
203
|
const { schemaName, codecHooks, storageTypes } = ctx;
|
|
204
|
+
// Per-table effective schema. `extra_table` issues intentionally
|
|
205
|
+
// omit `namespaceId` — the live DB carries a table that
|
|
206
|
+
// is not claimed by any contract namespace, so there is no contract
|
|
207
|
+
// coordinate to project from. Those issues fall back to the planner's
|
|
208
|
+
// global `ctx.schemaName`; every other issue dispatches through the
|
|
209
|
+
// resolved namespace's polymorphic `ddlSchemaName`.
|
|
210
|
+
const tableSchema = (issue: SchemaIssue): string => {
|
|
211
|
+
if (issue.kind === 'extra_table') return schemaName;
|
|
212
|
+
if (!('table' in issue) || !issue.table) return schemaName;
|
|
213
|
+
return resolveDdlSchemaForNamespace(ctx, resolveNamespaceIdForIssue(issue));
|
|
214
|
+
};
|
|
186
215
|
|
|
187
216
|
switch (issue.kind) {
|
|
217
|
+
case 'missing_schema': {
|
|
218
|
+
const namespaceId = issue.namespaceId;
|
|
219
|
+
if (!namespaceId)
|
|
220
|
+
return notOk(
|
|
221
|
+
issueConflict('unsupportedOperation', 'Missing schema issue has no namespaceId'),
|
|
222
|
+
);
|
|
223
|
+
const ddlSchemaName = resolveDdlSchemaForNamespace(ctx, namespaceId);
|
|
224
|
+
return ok([new CreateSchemaCall(ddlSchemaName)]);
|
|
225
|
+
}
|
|
226
|
+
|
|
188
227
|
case 'missing_table': {
|
|
189
228
|
if (!issue.table)
|
|
190
229
|
return notOk(
|
|
191
230
|
issueConflict('unsupportedOperation', 'Missing table issue has no table name'),
|
|
192
231
|
);
|
|
193
|
-
const
|
|
232
|
+
const namespaceId = resolveNamespaceIdForIssue(issue);
|
|
233
|
+
const contractTable = tableAt(ctx.toContract.storage, namespaceId, issue.table);
|
|
194
234
|
if (!contractTable) {
|
|
195
235
|
return notOk(
|
|
196
236
|
issueConflict(
|
|
197
237
|
'unsupportedOperation',
|
|
198
|
-
`Table "${issue.table}" reported missing but not found in destination contract`,
|
|
238
|
+
`Table "${issue.table}" in namespace "${namespaceId}" reported missing but not found in destination contract`,
|
|
199
239
|
),
|
|
200
240
|
);
|
|
201
241
|
}
|
|
242
|
+
const schemaForTable = tableSchema(issue);
|
|
202
243
|
const columns: ColumnSpec[] = Object.entries(contractTable.columns).map(([name, column]) =>
|
|
203
244
|
toColumnSpec(name, column, codecHooks, storageTypes),
|
|
204
245
|
);
|
|
@@ -206,7 +247,7 @@ function mapIssueToCall(
|
|
|
206
247
|
? { columns: contractTable.primaryKey.columns }
|
|
207
248
|
: undefined;
|
|
208
249
|
const calls: PostgresOpFactoryCall[] = [
|
|
209
|
-
new CreateTableCall(
|
|
250
|
+
new CreateTableCall(schemaForTable, issue.table, columns, primaryKey),
|
|
210
251
|
];
|
|
211
252
|
for (const index of contractTable.indexes) {
|
|
212
253
|
const indexName = index.name ?? `${issue.table}_${index.columns.join('_')}_idx`;
|
|
@@ -214,7 +255,7 @@ function mapIssueToCall(
|
|
|
214
255
|
if (index.type !== undefined) extras.type = index.type;
|
|
215
256
|
if (index.options !== undefined) extras.options = index.options;
|
|
216
257
|
calls.push(
|
|
217
|
-
new CreateIndexCall(
|
|
258
|
+
new CreateIndexCall(schemaForTable, issue.table, indexName, [...index.columns], extras),
|
|
218
259
|
);
|
|
219
260
|
}
|
|
220
261
|
const explicitIndexColumnSets = new Set(
|
|
@@ -222,24 +263,32 @@ function mapIssueToCall(
|
|
|
222
263
|
);
|
|
223
264
|
for (const fk of contractTable.foreignKeys) {
|
|
224
265
|
if (fk.constraint) {
|
|
225
|
-
const fkName = fk.name ?? `${issue.table}_${fk.columns.join('_')}_fkey`;
|
|
266
|
+
const fkName = fk.name ?? `${issue.table}_${fk.source.columns.join('_')}_fkey`;
|
|
226
267
|
const fkSpec: ForeignKeySpec = {
|
|
227
268
|
name: fkName,
|
|
228
|
-
columns: fk.columns,
|
|
229
|
-
references: {
|
|
269
|
+
columns: fk.source.columns,
|
|
270
|
+
references: {
|
|
271
|
+
schema: fk.target.namespaceId,
|
|
272
|
+
table: fk.target.tableName,
|
|
273
|
+
columns: fk.target.columns,
|
|
274
|
+
},
|
|
230
275
|
...(fk.onDelete !== undefined && { onDelete: fk.onDelete }),
|
|
231
276
|
...(fk.onUpdate !== undefined && { onUpdate: fk.onUpdate }),
|
|
232
277
|
};
|
|
233
|
-
calls.push(new AddForeignKeyCall(
|
|
278
|
+
calls.push(new AddForeignKeyCall(schemaForTable, issue.table, fkSpec));
|
|
234
279
|
}
|
|
235
|
-
if (fk.index && !explicitIndexColumnSets.has(fk.columns.join(','))) {
|
|
236
|
-
const indexName = `${issue.table}_${fk.columns.join('_')}_idx`;
|
|
237
|
-
calls.push(
|
|
280
|
+
if (fk.index && !explicitIndexColumnSets.has(fk.source.columns.join(','))) {
|
|
281
|
+
const indexName = `${issue.table}_${fk.source.columns.join('_')}_idx`;
|
|
282
|
+
calls.push(
|
|
283
|
+
new CreateIndexCall(schemaForTable, issue.table, indexName, [...fk.source.columns]),
|
|
284
|
+
);
|
|
238
285
|
}
|
|
239
286
|
}
|
|
240
287
|
for (const unique of contractTable.uniques) {
|
|
241
288
|
const constraintName = unique.name ?? `${issue.table}_${unique.columns.join('_')}_key`;
|
|
242
|
-
calls.push(
|
|
289
|
+
calls.push(
|
|
290
|
+
new AddUniqueCall(schemaForTable, issue.table, constraintName, [...unique.columns]),
|
|
291
|
+
);
|
|
243
292
|
}
|
|
244
293
|
return ok(calls);
|
|
245
294
|
}
|
|
@@ -250,7 +299,10 @@ function mapIssueToCall(
|
|
|
250
299
|
issueConflict('unsupportedOperation', 'Missing column issue has no table/column name'),
|
|
251
300
|
);
|
|
252
301
|
{
|
|
253
|
-
const
|
|
302
|
+
const namespaceId = resolveNamespaceIdForIssue(issue);
|
|
303
|
+
const column = tableAt(ctx.toContract.storage, namespaceId, issue.table)?.columns[
|
|
304
|
+
issue.column
|
|
305
|
+
];
|
|
254
306
|
if (!column)
|
|
255
307
|
return notOk(
|
|
256
308
|
issueConflict(
|
|
@@ -260,7 +312,7 @@ function mapIssueToCall(
|
|
|
260
312
|
);
|
|
261
313
|
return ok([
|
|
262
314
|
new AddColumnCall(
|
|
263
|
-
|
|
315
|
+
tableSchema(issue),
|
|
264
316
|
issue.table,
|
|
265
317
|
toColumnSpec(issue.column, column, codecHooks, storageTypes),
|
|
266
318
|
),
|
|
@@ -273,7 +325,10 @@ function mapIssueToCall(
|
|
|
273
325
|
issueConflict('unsupportedOperation', 'Default missing issue has no table/column name'),
|
|
274
326
|
);
|
|
275
327
|
{
|
|
276
|
-
const
|
|
328
|
+
const namespaceId = resolveNamespaceIdForIssue(issue);
|
|
329
|
+
const column = tableAt(ctx.toContract.storage, namespaceId, issue.table)?.columns[
|
|
330
|
+
issue.column
|
|
331
|
+
];
|
|
277
332
|
if (!column?.default) {
|
|
278
333
|
return notOk(
|
|
279
334
|
issueConflict(
|
|
@@ -284,27 +339,27 @@ function mapIssueToCall(
|
|
|
284
339
|
}
|
|
285
340
|
const defaultSql = buildColumnDefaultSql(column.default, column);
|
|
286
341
|
if (!defaultSql) return ok([]);
|
|
287
|
-
return ok([new SetDefaultCall(
|
|
342
|
+
return ok([new SetDefaultCall(tableSchema(issue), issue.table, issue.column, defaultSql)]);
|
|
288
343
|
}
|
|
289
344
|
|
|
290
345
|
case 'extra_table':
|
|
291
346
|
if (!issue.table)
|
|
292
347
|
return notOk(issueConflict('unsupportedOperation', 'Extra table issue has no table name'));
|
|
293
|
-
return ok([new DropTableCall(
|
|
348
|
+
return ok([new DropTableCall(tableSchema(issue), issue.table)]);
|
|
294
349
|
|
|
295
350
|
case 'extra_column':
|
|
296
351
|
if (!issue.table || !issue.column)
|
|
297
352
|
return notOk(
|
|
298
353
|
issueConflict('unsupportedOperation', 'Extra column issue has no table/column name'),
|
|
299
354
|
);
|
|
300
|
-
return ok([new DropColumnCall(
|
|
355
|
+
return ok([new DropColumnCall(tableSchema(issue), issue.table, issue.column)]);
|
|
301
356
|
|
|
302
357
|
case 'extra_index':
|
|
303
358
|
if (!issue.table || !issue.indexOrConstraint)
|
|
304
359
|
return notOk(
|
|
305
360
|
issueConflict('unsupportedOperation', 'Extra index issue has no table/index name'),
|
|
306
361
|
);
|
|
307
|
-
return ok([new DropIndexCall(
|
|
362
|
+
return ok([new DropIndexCall(tableSchema(issue), issue.table, issue.indexOrConstraint)]);
|
|
308
363
|
|
|
309
364
|
case 'extra_unique_constraint':
|
|
310
365
|
case 'extra_foreign_key':
|
|
@@ -336,7 +391,12 @@ function mapIssueToCall(
|
|
|
336
391
|
extra_primary_key: 'primaryKey' as const,
|
|
337
392
|
};
|
|
338
393
|
return ok([
|
|
339
|
-
new DropConstraintCall(
|
|
394
|
+
new DropConstraintCall(
|
|
395
|
+
tableSchema(issue),
|
|
396
|
+
issue.table,
|
|
397
|
+
constraintName,
|
|
398
|
+
kindMap[issue.kind],
|
|
399
|
+
),
|
|
340
400
|
]);
|
|
341
401
|
}
|
|
342
402
|
|
|
@@ -345,14 +405,17 @@ function mapIssueToCall(
|
|
|
345
405
|
return notOk(
|
|
346
406
|
issueConflict('unsupportedOperation', 'Extra default issue has no table/column name'),
|
|
347
407
|
);
|
|
348
|
-
return ok([new DropDefaultCall(
|
|
408
|
+
return ok([new DropDefaultCall(tableSchema(issue), issue.table, issue.column)]);
|
|
349
409
|
|
|
350
410
|
case 'nullability_mismatch': {
|
|
351
411
|
if (!issue.table || !issue.column)
|
|
352
412
|
return notOk(
|
|
353
413
|
issueConflict('nullabilityConflict', 'Nullability mismatch has no table/column name'),
|
|
354
414
|
);
|
|
355
|
-
const
|
|
415
|
+
const namespaceId = resolveNamespaceIdForIssue(issue);
|
|
416
|
+
const column = tableAt(ctx.toContract.storage, namespaceId, issue.table)?.columns[
|
|
417
|
+
issue.column
|
|
418
|
+
];
|
|
356
419
|
if (!column)
|
|
357
420
|
return notOk(
|
|
358
421
|
issueConflict(
|
|
@@ -360,10 +423,11 @@ function mapIssueToCall(
|
|
|
360
423
|
`Column "${issue.table}"."${issue.column}" not found in destination contract`,
|
|
361
424
|
),
|
|
362
425
|
);
|
|
426
|
+
const schemaForTable = tableSchema(issue);
|
|
363
427
|
return ok(
|
|
364
428
|
column.nullable
|
|
365
|
-
? [new DropNotNullCall(
|
|
366
|
-
: [new SetNotNullCall(
|
|
429
|
+
? [new DropNotNullCall(schemaForTable, issue.table, issue.column)]
|
|
430
|
+
: [new SetNotNullCall(schemaForTable, issue.table, issue.column)],
|
|
367
431
|
);
|
|
368
432
|
}
|
|
369
433
|
|
|
@@ -371,7 +435,10 @@ function mapIssueToCall(
|
|
|
371
435
|
if (!issue.table || !issue.column)
|
|
372
436
|
return notOk(issueConflict('typeMismatch', 'Type mismatch has no table/column name'));
|
|
373
437
|
{
|
|
374
|
-
const
|
|
438
|
+
const namespaceId = resolveNamespaceIdForIssue(issue);
|
|
439
|
+
const column = tableAt(ctx.toContract.storage, namespaceId, issue.table)?.columns[
|
|
440
|
+
issue.column
|
|
441
|
+
];
|
|
375
442
|
if (!column)
|
|
376
443
|
return notOk(
|
|
377
444
|
issueConflict(
|
|
@@ -387,7 +454,7 @@ function mapIssueToCall(
|
|
|
387
454
|
const qualifiedTargetType = buildColumnTypeSql(column, hooksMap, typesMap, false);
|
|
388
455
|
const formatTypeExpected = buildExpectedFormatType(column, hooksMap, typesMap);
|
|
389
456
|
return ok([
|
|
390
|
-
new AlterColumnTypeCall(
|
|
457
|
+
new AlterColumnTypeCall(tableSchema(issue), issue.table, issue.column, {
|
|
391
458
|
qualifiedTargetType,
|
|
392
459
|
formatTypeExpected,
|
|
393
460
|
rawTargetTypeForLabel: qualifiedTargetType,
|
|
@@ -401,12 +468,15 @@ function mapIssueToCall(
|
|
|
401
468
|
issueConflict('unsupportedOperation', 'Default mismatch has no table/column name'),
|
|
402
469
|
);
|
|
403
470
|
{
|
|
404
|
-
const
|
|
471
|
+
const namespaceId = resolveNamespaceIdForIssue(issue);
|
|
472
|
+
const column = tableAt(ctx.toContract.storage, namespaceId, issue.table)?.columns[
|
|
473
|
+
issue.column
|
|
474
|
+
];
|
|
405
475
|
if (!column?.default) return ok([]);
|
|
406
476
|
const defaultSql = buildColumnDefaultSql(column.default, column);
|
|
407
477
|
if (!defaultSql) return ok([]);
|
|
408
478
|
return ok([
|
|
409
|
-
new SetDefaultCall(
|
|
479
|
+
new SetDefaultCall(tableSchema(issue), issue.table, issue.column, defaultSql, 'widening'),
|
|
410
480
|
]);
|
|
411
481
|
}
|
|
412
482
|
|
|
@@ -414,13 +484,16 @@ function mapIssueToCall(
|
|
|
414
484
|
if (!issue.table)
|
|
415
485
|
return notOk(issueConflict('indexIncompatible', 'Primary key issue has no table name'));
|
|
416
486
|
if (isMissing(issue)) {
|
|
417
|
-
const
|
|
487
|
+
const namespaceId = resolveNamespaceIdForIssue(issue);
|
|
488
|
+
const pk = tableAt(ctx.toContract.storage, namespaceId, issue.table)?.primaryKey;
|
|
418
489
|
if (!pk)
|
|
419
490
|
return notOk(
|
|
420
491
|
issueConflict('indexIncompatible', `No primary key in contract for "${issue.table}"`),
|
|
421
492
|
);
|
|
422
493
|
const constraintName = pk.name ?? `${issue.table}_pkey`;
|
|
423
|
-
return ok([
|
|
494
|
+
return ok([
|
|
495
|
+
new AddPrimaryKeyCall(tableSchema(issue), issue.table, constraintName, pk.columns),
|
|
496
|
+
]);
|
|
424
497
|
}
|
|
425
498
|
return notOk(
|
|
426
499
|
issueConflict(
|
|
@@ -438,7 +511,7 @@ function mapIssueToCall(
|
|
|
438
511
|
if (isMissing(issue) && issue.expected) {
|
|
439
512
|
const columns = issue.expected.split(', ');
|
|
440
513
|
const constraintName = `${issue.table}_${columns.join('_')}_key`;
|
|
441
|
-
return ok([new AddUniqueCall(
|
|
514
|
+
return ok([new AddUniqueCall(tableSchema(issue), issue.table, constraintName, columns)]);
|
|
442
515
|
}
|
|
443
516
|
return notOk(
|
|
444
517
|
issueConflict(
|
|
@@ -452,15 +525,22 @@ function mapIssueToCall(
|
|
|
452
525
|
if (!issue.table)
|
|
453
526
|
return notOk(issueConflict('indexIncompatible', 'Index issue has no table name'));
|
|
454
527
|
if (isMissing(issue) && issue.expected) {
|
|
528
|
+
const namespaceId = resolveNamespaceIdForIssue(issue);
|
|
455
529
|
const columns = issue.expected.split(', ');
|
|
456
|
-
const contractIndex =
|
|
530
|
+
const contractIndex = tableAt(
|
|
531
|
+
ctx.toContract.storage,
|
|
532
|
+
namespaceId,
|
|
533
|
+
issue.table,
|
|
534
|
+
)?.indexes.find((idx: StorageTable['indexes'][number]) =>
|
|
457
535
|
arraysEqual(idx.columns, columns),
|
|
458
536
|
);
|
|
459
537
|
const indexName = contractIndex?.name ?? `${issue.table}_${columns.join('_')}_idx`;
|
|
460
538
|
const extras: { type?: string; options?: Record<string, unknown> } = {};
|
|
461
539
|
if (contractIndex?.type !== undefined) extras.type = contractIndex.type;
|
|
462
540
|
if (contractIndex?.options !== undefined) extras.options = contractIndex.options;
|
|
463
|
-
return ok([
|
|
541
|
+
return ok([
|
|
542
|
+
new CreateIndexCall(tableSchema(issue), issue.table, indexName, columns, extras),
|
|
543
|
+
]);
|
|
464
544
|
}
|
|
465
545
|
return notOk(
|
|
466
546
|
issueConflict(
|
|
@@ -476,20 +556,25 @@ function mapIssueToCall(
|
|
|
476
556
|
if (isMissing(issue) && issue.expected) {
|
|
477
557
|
const arrowIdx = issue.expected.indexOf(' -> ');
|
|
478
558
|
if (arrowIdx >= 0) {
|
|
559
|
+
const namespaceId = resolveNamespaceIdForIssue(issue);
|
|
479
560
|
const columns = issue.expected.slice(0, arrowIdx).split(', ');
|
|
480
561
|
const fkName = `${issue.table}_${columns.join('_')}_fkey`;
|
|
481
|
-
const fk = ctx.toContract.storage
|
|
482
|
-
(k) => k.columns.join(', ') === columns.join(', '),
|
|
562
|
+
const fk = tableAt(ctx.toContract.storage, namespaceId, issue.table)?.foreignKeys.find(
|
|
563
|
+
(k) => k.source.columns.join(', ') === columns.join(', '),
|
|
483
564
|
);
|
|
484
565
|
if (fk) {
|
|
485
566
|
const fkSpec: ForeignKeySpec = {
|
|
486
567
|
name: fkName,
|
|
487
|
-
columns: fk.columns,
|
|
488
|
-
references: {
|
|
568
|
+
columns: fk.source.columns,
|
|
569
|
+
references: {
|
|
570
|
+
schema: fk.target.namespaceId,
|
|
571
|
+
table: fk.target.tableName,
|
|
572
|
+
columns: fk.target.columns,
|
|
573
|
+
},
|
|
489
574
|
...(fk.onDelete !== undefined && { onDelete: fk.onDelete }),
|
|
490
575
|
...(fk.onUpdate !== undefined && { onUpdate: fk.onUpdate }),
|
|
491
576
|
};
|
|
492
|
-
return ok([new AddForeignKeyCall(
|
|
577
|
+
return ok([new AddForeignKeyCall(tableSchema(issue), issue.table, fkSpec)]);
|
|
493
578
|
}
|
|
494
579
|
return notOk(
|
|
495
580
|
issueConflict(
|
|
@@ -511,7 +596,11 @@ function mapIssueToCall(
|
|
|
511
596
|
case 'type_missing': {
|
|
512
597
|
if (!issue.typeName)
|
|
513
598
|
return notOk(issueConflict('unsupportedOperation', 'Type missing issue has no typeName'));
|
|
514
|
-
|
|
599
|
+
// Enum types live in namespace.types; codec aliases live in storage.types.
|
|
600
|
+
// Check both so the planner handles whichever slot the type is in.
|
|
601
|
+
const typeInstance: unknown =
|
|
602
|
+
ctx.toContract.storage.types?.[issue.typeName] ??
|
|
603
|
+
locateNamespaceTypeInStorage(ctx.toContract.storage, issue.typeName);
|
|
515
604
|
if (!typeInstance) {
|
|
516
605
|
return notOk(
|
|
517
606
|
issueConflict(
|
|
@@ -530,10 +619,11 @@ function mapIssueToCall(
|
|
|
530
619
|
),
|
|
531
620
|
]);
|
|
532
621
|
}
|
|
622
|
+
const codecInstance = typeInstance as StorageTypeInstance;
|
|
533
623
|
return notOk(
|
|
534
624
|
issueConflict(
|
|
535
625
|
'unsupportedOperation',
|
|
536
|
-
`Type "${issue.typeName}" uses codec "${
|
|
626
|
+
`Type "${issue.typeName}" uses codec "${codecInstance.codecId}" — only enum types are supported`,
|
|
537
627
|
),
|
|
538
628
|
);
|
|
539
629
|
}
|
|
@@ -15,7 +15,7 @@ function renderForeignKeySql(schemaName: string, tableName: string, fk: ForeignK
|
|
|
15
15
|
let sql = `ALTER TABLE ${qualifyTableName(schemaName, tableName)}
|
|
16
16
|
ADD CONSTRAINT ${quoteIdentifier(fk.name)}
|
|
17
17
|
FOREIGN KEY (${fk.columns.map(quoteIdentifier).join(', ')})
|
|
18
|
-
REFERENCES ${qualifyTableName(
|
|
18
|
+
REFERENCES ${qualifyTableName(fk.references.schema, fk.references.table)} (${fk.references.columns
|
|
19
19
|
.map(quoteIdentifier)
|
|
20
20
|
.join(', ')})`;
|
|
21
21
|
|
|
@@ -26,13 +26,15 @@ export interface ColumnSpec {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* Literal-args shape for a foreign key definition.
|
|
30
|
-
*
|
|
29
|
+
* Literal-args shape for a foreign key definition. `references.schema`
|
|
30
|
+
* carries the target table's namespace (schema) coordinate so the rendered
|
|
31
|
+
* DDL qualifies the REFERENCES clause correctly for cross-schema FKs.
|
|
31
32
|
*/
|
|
32
33
|
export interface ForeignKeySpec {
|
|
33
34
|
readonly name: string;
|
|
34
35
|
readonly columns: readonly string[];
|
|
35
36
|
readonly references: {
|
|
37
|
+
readonly schema: string;
|
|
36
38
|
readonly table: string;
|
|
37
39
|
readonly columns: readonly string[];
|
|
38
40
|
};
|
|
@@ -233,8 +233,8 @@ export function buildForeignKeySql(
|
|
|
233
233
|
): string {
|
|
234
234
|
let sql = `ALTER TABLE ${qualifyTableName(schemaName, tableName)}
|
|
235
235
|
ADD CONSTRAINT ${quoteIdentifier(fkName)}
|
|
236
|
-
FOREIGN KEY (${foreignKey.columns.map(quoteIdentifier).join(', ')})
|
|
237
|
-
REFERENCES ${qualifyTableName(schemaName, foreignKey.
|
|
236
|
+
FOREIGN KEY (${foreignKey.source.columns.map(quoteIdentifier).join(', ')})
|
|
237
|
+
REFERENCES ${qualifyTableName(schemaName, foreignKey.target.tableName)} (${foreignKey.target.columns
|
|
238
238
|
.map(quoteIdentifier)
|
|
239
239
|
.join(', ')})`;
|
|
240
240
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
1
2
|
import type { ForeignKey } from '@prisma-next/sql-contract/types';
|
|
2
3
|
import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
3
4
|
|
|
@@ -26,11 +27,21 @@ function buildSchemaTableLookup(table: SqlSchemaIR['tables'][string]): SchemaTab
|
|
|
26
27
|
const uniqueIndexKeys = new Set(
|
|
27
28
|
table.indexes.filter((i) => i.unique).map((i) => i.columns.join(',')),
|
|
28
29
|
);
|
|
29
|
-
const fkKeys = new Set(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
|
|
30
|
+
const fkKeys = new Set<string>();
|
|
31
|
+
for (const fk of table.foreignKeys) {
|
|
32
|
+
// Keys are JSON-encoded tuples so identifiers containing any character
|
|
33
|
+
// (including the column-list comma or pipe characters) cannot collide
|
|
34
|
+
// across structurally-distinct FKs. Unqualified keys are 3-tuples
|
|
35
|
+
// (cols, table, refCols); qualified keys are 4-tuples
|
|
36
|
+
// (cols, schema, table, refCols) — the arity difference makes the two
|
|
37
|
+
// key shapes fundamentally non-collidable.
|
|
38
|
+
fkKeys.add(JSON.stringify([fk.columns, fk.referencedTable, fk.referencedColumns]));
|
|
39
|
+
if (fk.referencedSchema !== undefined) {
|
|
40
|
+
fkKeys.add(
|
|
41
|
+
JSON.stringify([fk.columns, fk.referencedSchema, fk.referencedTable, fk.referencedColumns]),
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
34
45
|
return { uniqueKeys, indexKeys, uniqueIndexKeys, fkKeys };
|
|
35
46
|
}
|
|
36
47
|
|
|
@@ -48,7 +59,20 @@ export function hasIndex(lookup: SchemaTableLookup, columns: readonly string[]):
|
|
|
48
59
|
}
|
|
49
60
|
|
|
50
61
|
export function hasForeignKey(lookup: SchemaTableLookup, fk: ForeignKey): boolean {
|
|
62
|
+
// Mirror the encoding produced by buildSchemaTableLookup exactly:
|
|
63
|
+
// unqualified 3-tuple for unbound-namespace FKs, qualified 4-tuple for
|
|
64
|
+
// bound-namespace FKs.
|
|
65
|
+
if (fk.target.namespaceId === UNBOUND_NAMESPACE_ID) {
|
|
66
|
+
return lookup.fkKeys.has(
|
|
67
|
+
JSON.stringify([fk.source.columns, fk.target.tableName, fk.target.columns]),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
51
70
|
return lookup.fkKeys.has(
|
|
52
|
-
|
|
71
|
+
JSON.stringify([
|
|
72
|
+
fk.source.columns,
|
|
73
|
+
fk.target.namespaceId,
|
|
74
|
+
fk.target.tableName,
|
|
75
|
+
fk.target.columns,
|
|
76
|
+
]),
|
|
53
77
|
);
|
|
54
78
|
}
|
|
@@ -4,16 +4,27 @@ import type {
|
|
|
4
4
|
StorageColumn,
|
|
5
5
|
StorageTypeInstance,
|
|
6
6
|
} from '@prisma-next/sql-contract/types';
|
|
7
|
+
import { postgresCreateNamespace } from '../postgres-schema';
|
|
7
8
|
import { escapeLiteral, quoteIdentifier } from '../sql-utils';
|
|
8
9
|
import { resolveColumnTypeMetadata } from './planner-type-resolution';
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* String-keyed entry points the migration ops use to render
|
|
13
|
+
* schema-qualified DDL and catalog checks. The `schema` argument is
|
|
14
|
+
* interpreted as a namespace coordinate: the framework `__unbound__`
|
|
15
|
+
* sentinel resolves to the late-bound `PostgresUnboundSchema` singleton
|
|
16
|
+
* (which elides the qualifier so `search_path` decides at runtime); any
|
|
17
|
+
* other id materialises a `PostgresSchema(id)` whose qualifier is the
|
|
18
|
+
* named schema. Helpers route through these `Namespace` concretions so
|
|
19
|
+
* the unbound branch lives in the polymorphic override, not the call
|
|
20
|
+
* site.
|
|
21
|
+
*/
|
|
10
22
|
export function qualifyTableName(schema: string, table: string): string {
|
|
11
|
-
return
|
|
23
|
+
return postgresCreateNamespace({ id: schema }).qualifyTable(table);
|
|
12
24
|
}
|
|
13
25
|
|
|
14
26
|
export function toRegclassLiteral(schema: string, name: string): string {
|
|
15
|
-
|
|
16
|
-
return `'${escapeLiteral(regclass)}'`;
|
|
27
|
+
return postgresCreateNamespace({ id: schema }).regclassLiteral(name);
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
/**
|
|
@@ -32,15 +43,16 @@ export function constraintExistsCheck({
|
|
|
32
43
|
table?: string;
|
|
33
44
|
exists?: boolean;
|
|
34
45
|
}): string {
|
|
46
|
+
const namespace = postgresCreateNamespace({ id: schema });
|
|
35
47
|
const existsClause = exists ? 'EXISTS' : 'NOT EXISTS';
|
|
36
48
|
const tableFilter = table
|
|
37
|
-
? `AND c.conrelid = to_regclass(${
|
|
49
|
+
? `AND c.conrelid = to_regclass(${namespace.regclassLiteral(table)})`
|
|
38
50
|
: '';
|
|
39
51
|
return `SELECT ${existsClause} (
|
|
40
52
|
SELECT 1 FROM pg_constraint c
|
|
41
53
|
JOIN pg_namespace n ON c.connamespace = n.oid
|
|
42
54
|
WHERE c.conname = '${escapeLiteral(constraintName)}'
|
|
43
|
-
AND n.nspname =
|
|
55
|
+
AND n.nspname = ${namespace.schemaSqlExpression()}
|
|
44
56
|
${tableFilter}
|
|
45
57
|
)`;
|
|
46
58
|
}
|
|
@@ -56,11 +68,12 @@ export function columnExistsCheck({
|
|
|
56
68
|
column: string;
|
|
57
69
|
exists?: boolean;
|
|
58
70
|
}): string {
|
|
71
|
+
const namespace = postgresCreateNamespace({ id: schema });
|
|
59
72
|
const existsClause = exists ? '' : 'NOT ';
|
|
60
73
|
return `SELECT ${existsClause}EXISTS (
|
|
61
74
|
SELECT 1
|
|
62
75
|
FROM information_schema.columns
|
|
63
|
-
WHERE table_schema =
|
|
76
|
+
WHERE table_schema = ${namespace.schemaSqlExpression()}
|
|
64
77
|
AND table_name = '${escapeLiteral(table)}'
|
|
65
78
|
AND column_name = '${escapeLiteral(column)}'
|
|
66
79
|
)`;
|
|
@@ -77,11 +90,12 @@ export function columnNullabilityCheck({
|
|
|
77
90
|
column: string;
|
|
78
91
|
nullable: boolean;
|
|
79
92
|
}): string {
|
|
93
|
+
const namespace = postgresCreateNamespace({ id: schema });
|
|
80
94
|
const expected = nullable ? 'YES' : 'NO';
|
|
81
95
|
return `SELECT EXISTS (
|
|
82
96
|
SELECT 1
|
|
83
97
|
FROM information_schema.columns
|
|
84
|
-
WHERE table_schema =
|
|
98
|
+
WHERE table_schema = ${namespace.schemaSqlExpression()}
|
|
85
99
|
AND table_name = '${escapeLiteral(table)}'
|
|
86
100
|
AND column_name = '${escapeLiteral(column)}'
|
|
87
101
|
AND is_nullable = '${expected}'
|
|
@@ -97,10 +111,11 @@ export function columnHasNoDefaultCheck(opts: {
|
|
|
97
111
|
table: string;
|
|
98
112
|
column: string;
|
|
99
113
|
}): string {
|
|
114
|
+
const namespace = postgresCreateNamespace({ id: opts.schema });
|
|
100
115
|
return `SELECT NOT EXISTS (
|
|
101
116
|
SELECT 1
|
|
102
117
|
FROM information_schema.columns
|
|
103
|
-
WHERE table_schema =
|
|
118
|
+
WHERE table_schema = ${namespace.schemaSqlExpression()}
|
|
104
119
|
AND table_name = '${escapeLiteral(opts.table)}'
|
|
105
120
|
AND column_name = '${escapeLiteral(opts.column)}'
|
|
106
121
|
AND column_default IS NOT NULL
|
|
@@ -267,12 +282,13 @@ export function columnTypeCheck({
|
|
|
267
282
|
column: string;
|
|
268
283
|
expectedType: string;
|
|
269
284
|
}): string {
|
|
285
|
+
const namespace = postgresCreateNamespace({ id: schema });
|
|
270
286
|
return `SELECT EXISTS (
|
|
271
287
|
SELECT 1
|
|
272
288
|
FROM pg_attribute a
|
|
273
289
|
JOIN pg_class c ON c.oid = a.attrelid
|
|
274
290
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
275
|
-
WHERE n.nspname =
|
|
291
|
+
WHERE n.nspname = ${namespace.schemaSqlExpression()}
|
|
276
292
|
AND c.relname = '${escapeLiteral(table)}'
|
|
277
293
|
AND a.attname = '${escapeLiteral(column)}'
|
|
278
294
|
AND format_type(a.atttypid, a.atttypmod) = '${escapeLiteral(expectedType)}'
|
|
@@ -291,11 +307,12 @@ export function columnDefaultExistsCheck({
|
|
|
291
307
|
column: string;
|
|
292
308
|
exists?: boolean;
|
|
293
309
|
}): string {
|
|
310
|
+
const namespace = postgresCreateNamespace({ id: schema });
|
|
294
311
|
const nullCheck = exists ? 'IS NOT NULL' : 'IS NULL';
|
|
295
312
|
return `SELECT EXISTS (
|
|
296
313
|
SELECT 1
|
|
297
314
|
FROM information_schema.columns
|
|
298
|
-
WHERE table_schema =
|
|
315
|
+
WHERE table_schema = ${namespace.schemaSqlExpression()}
|
|
299
316
|
AND table_name = '${escapeLiteral(table)}'
|
|
300
317
|
AND column_name = '${escapeLiteral(column)}'
|
|
301
318
|
AND column_default ${nullCheck}
|
|
@@ -308,6 +325,7 @@ export function tableHasPrimaryKeyCheck(
|
|
|
308
325
|
exists: boolean,
|
|
309
326
|
constraintName?: string,
|
|
310
327
|
): string {
|
|
328
|
+
const namespace = postgresCreateNamespace({ id: schema });
|
|
311
329
|
const comparison = exists ? '' : 'NOT ';
|
|
312
330
|
const constraintFilter = constraintName
|
|
313
331
|
? `AND c2.relname = '${escapeLiteral(constraintName)}'`
|
|
@@ -318,7 +336,7 @@ export function tableHasPrimaryKeyCheck(
|
|
|
318
336
|
JOIN pg_class c ON c.oid = i.indrelid
|
|
319
337
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
320
338
|
LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
|
|
321
|
-
WHERE n.nspname =
|
|
339
|
+
WHERE n.nspname = ${namespace.schemaSqlExpression()}
|
|
322
340
|
AND c.relname = '${escapeLiteral(table)}'
|
|
323
341
|
AND i.indisprimary
|
|
324
342
|
${constraintFilter}
|