@everystack/cli 0.3.19 → 0.3.22
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/README.md +2 -0
- package/package.json +2 -2
- package/src/cli/commands/db-apply.ts +233 -0
- package/src/cli/commands/db-check.ts +306 -0
- package/src/cli/commands/db-plan.ts +123 -0
- package/src/cli/commands/db-sync.ts +1 -1
- package/src/cli/edge-plan.ts +195 -0
- package/src/cli/git-descent.ts +251 -0
- package/src/cli/index.ts +15 -0
- package/src/cli/migration-generate.ts +35 -5
- package/src/cli/schema-compile.ts +17 -0
- package/src/cli/schema-diff.ts +52 -5
package/src/cli/schema-diff.ts
CHANGED
|
@@ -65,6 +65,12 @@ export type SchemaChange =
|
|
|
65
65
|
| { kind: 'renameSourceMissing'; table: string; column: string; from: string }
|
|
66
66
|
/** An unmarked drop+add that *might* be a rename — a hint comment, the SQL still drops+adds. */
|
|
67
67
|
| { kind: 'renameHint'; table: string; from: string; to: string }
|
|
68
|
+
/** A table-level `renamedFrom` satisfied: old table present, new absent → one RENAME, data preserved. */
|
|
69
|
+
| { kind: 'renameTable'; from: string; to: string }
|
|
70
|
+
/** A table marker whose rename is already applied (new name present) — inert, a notice. */
|
|
71
|
+
| { kind: 'renameTableSatisfied'; table: string; from: string }
|
|
72
|
+
/** A table marker pointing at a table the database doesn't have — fell back to CREATE, a notice. */
|
|
73
|
+
| { kind: 'renameTableSourceMissing'; table: string; from: string }
|
|
68
74
|
/** A new enum type → `CREATE TYPE … AS ENUM (…)`, emitted before the tables that use it. */
|
|
69
75
|
| { kind: 'createType'; name: string; values: string[] }
|
|
70
76
|
/** A value appended to an existing enum → `ALTER TYPE … ADD VALUE` (carries a -- WARNING). */
|
|
@@ -86,6 +92,14 @@ export type SchemaChange =
|
|
|
86
92
|
*/
|
|
87
93
|
export type RenameMap = Record<string, Record<string, string>>;
|
|
88
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Table-level rename intent: qualified new name → qualified old name. Produced
|
|
97
|
+
* by `compileTableRenames` off the Models' `renamedFrom` option; consumed by
|
|
98
|
+
* `diffSchema`'s pre-pass, which rewrites the current snapshot (old table seen
|
|
99
|
+
* as the new name) so every downstream diff lands on the renamed table.
|
|
100
|
+
*/
|
|
101
|
+
export type TableRenameMap = Record<string, string>;
|
|
102
|
+
|
|
89
103
|
// ---------------------------------------------------------------------------
|
|
90
104
|
// Normalization — so semantically-equal expressions don't read as drift.
|
|
91
105
|
// ---------------------------------------------------------------------------
|
|
@@ -232,8 +246,9 @@ export function normalizeCheck(expr: string): string {
|
|
|
232
246
|
* replaced constraint never clashes with its old self and a column is never dropped out
|
|
233
247
|
* from under a constraint that still references it.
|
|
234
248
|
*/
|
|
235
|
-
export function diffSchema(desired: SchemaSnapshot, current: SchemaSnapshot, renames: RenameMap = {}): SchemaChange[] {
|
|
249
|
+
export function diffSchema(desired: SchemaSnapshot, current: SchemaSnapshot, renames: RenameMap = {}, tableRenames: TableRenameMap = {}): SchemaChange[] {
|
|
236
250
|
const creates: SchemaChange[] = [];
|
|
251
|
+
const renameTables: SchemaChange[] = [];
|
|
237
252
|
const renameColumns: SchemaChange[] = [];
|
|
238
253
|
const addColumns: SchemaChange[] = [];
|
|
239
254
|
const alters: SchemaChange[] = [];
|
|
@@ -248,6 +263,28 @@ export function diffSchema(desired: SchemaSnapshot, current: SchemaSnapshot, ren
|
|
|
248
263
|
const currentByName = new Map(current.tables.map((t) => [t.table, t]));
|
|
249
264
|
const desiredNames = new Set(desired.tables.map((t) => t.table));
|
|
250
265
|
|
|
266
|
+
// Table-rename pre-pass: honor the Models' table-level `renamedFrom` before
|
|
267
|
+
// any matching. A satisfied rename rewrites the current snapshot — the old
|
|
268
|
+
// table is seen under its new name — so every downstream diff (columns,
|
|
269
|
+
// constraints, indexes, drops) lands on the renamed table, and the old name
|
|
270
|
+
// never reaches the dropTables sweep. Mirrors the column-rename semantics:
|
|
271
|
+
// new-name-present → inert notice; source missing → CREATE path + notice.
|
|
272
|
+
for (const [to, from] of Object.entries(tableRenames)) {
|
|
273
|
+
if (!desiredNames.has(to)) continue; // the marker's model isn't in this diff
|
|
274
|
+
if (currentByName.has(to)) {
|
|
275
|
+
notices.push({ kind: 'renameTableSatisfied', table: to, from });
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
const source = currentByName.get(from);
|
|
279
|
+
if (!source) {
|
|
280
|
+
notices.push({ kind: 'renameTableSourceMissing', table: to, from });
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
renameTables.push({ kind: 'renameTable', from, to });
|
|
284
|
+
currentByName.delete(from);
|
|
285
|
+
currentByName.set(to, { ...source, table: to });
|
|
286
|
+
}
|
|
287
|
+
|
|
251
288
|
for (const d of desired.tables) {
|
|
252
289
|
const c = currentByName.get(d.table);
|
|
253
290
|
if (!c) {
|
|
@@ -274,18 +311,21 @@ export function diffSchema(desired: SchemaSnapshot, current: SchemaSnapshot, ren
|
|
|
274
311
|
diffIndexes(d, c, createIndexes, dropIndexes);
|
|
275
312
|
}
|
|
276
313
|
|
|
277
|
-
|
|
314
|
+
// Sweep the POST-RENAME view: a renamed-away old name is not a drop.
|
|
315
|
+
for (const c of currentByName.values()) {
|
|
278
316
|
if (!desiredNames.has(c.table)) dropTables.push({ kind: 'dropTable', table: c.table });
|
|
279
317
|
}
|
|
280
318
|
|
|
281
319
|
const e = diffEnums(desired.enums ?? [], current.enums ?? []);
|
|
282
320
|
|
|
283
321
|
// Enum types come first (a table or column may reference one); value adds before the
|
|
284
|
-
// columns that use them.
|
|
285
|
-
// reuse) and before
|
|
286
|
-
//
|
|
322
|
+
// columns that use them. Table renames run before creates (a rename frees a name a
|
|
323
|
+
// create may reuse) and before every per-table change (which all target the new name).
|
|
324
|
+
// Column renames run before adds and alters for the same reason. Enum drops sit with
|
|
325
|
+
// the other removals; notices are comments — emitted last, after the DDL.
|
|
287
326
|
return [
|
|
288
327
|
...e.creates, ...e.adds,
|
|
328
|
+
...renameTables,
|
|
289
329
|
...creates, ...renameColumns, ...addColumns, ...alters,
|
|
290
330
|
...dropConstraints, ...addConstraints, ...createIndexes,
|
|
291
331
|
...dropColumns, ...dropIndexes, ...dropTables,
|
|
@@ -613,6 +653,13 @@ function emitOne(change: SchemaChange, opts: EmitOptions): string {
|
|
|
613
653
|
return `-- NOTICE: primary key on ${change.table} changed (${change.from.join(', ')} → ${change.to.join(', ')}); dropping a primary key needs its constraint name — regenerate this change manually.`;
|
|
614
654
|
case 'renameColumn':
|
|
615
655
|
return `ALTER TABLE ${change.table} RENAME COLUMN ${quote(change.from)} TO ${quote(change.to)};`;
|
|
656
|
+
case 'renameTable':
|
|
657
|
+
// RENAME TO takes a bare name — the table stays in its schema.
|
|
658
|
+
return `ALTER TABLE ${change.from} RENAME TO ${quote(change.to.split('.').pop()!)};`;
|
|
659
|
+
case 'renameTableSatisfied':
|
|
660
|
+
return `-- NOTICE: the renamedFrom marker on table ${change.table} is satisfied — the rename from "${change.from}" is applied, the marker is now inert and can be removed.`;
|
|
661
|
+
case 'renameTableSourceMissing':
|
|
662
|
+
return `-- NOTICE: table ${change.table} declares renamedFrom "${change.from}", but the database has neither — created fresh; remove the marker once every environment is past it.`;
|
|
616
663
|
case 'renameSatisfied':
|
|
617
664
|
return `-- NOTICE: the renamedFrom marker on column ${quote(change.column)} (${change.table}) is satisfied — the rename from "${change.from}" is applied, the marker is now inert and can be removed.`;
|
|
618
665
|
case 'renameSourceMissing':
|