@substrat-run/model-emit 0.3.2 → 0.4.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/README.md +32 -3
- package/dist/emit-sql.d.ts +17 -1
- package/dist/emit-sql.d.ts.map +1 -1
- package/dist/emit-sql.js +36 -6
- package/dist/emit-sql.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/journal.d.ts +20 -0
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +76 -0
- package/dist/journal.js.map +1 -1
- package/dist/plan.d.ts +1 -1
- package/dist/plan.d.ts.map +1 -1
- package/dist/plan.js +37 -12
- package/dist/plan.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -50,6 +50,9 @@ const sql = emitTables(entities);
|
|
|
50
50
|
| declared | emitted |
|
|
51
51
|
|---|---|
|
|
52
52
|
| `id` | `id TEXT PRIMARY KEY NOT NULL` |
|
|
53
|
+
| `primaryKey: ['workorder_id']` | `workorder_id TEXT PRIMARY KEY NOT NULL` — the identity of a side table keyed by an engine's id |
|
|
54
|
+
| `primaryKey: ['customer_id','year']` | `PRIMARY KEY (customer_id, year)` as a table-level constraint, in declaration order |
|
|
55
|
+
| neither an `id` field nor a `primaryKey` | **refused** — a table with no primary key accepts duplicate rows |
|
|
53
56
|
| `z.string()` / `.nullable()` | `TEXT NOT NULL` / `TEXT` |
|
|
54
57
|
| `z.number()` | `INTEGER` |
|
|
55
58
|
| `z.boolean()` | **refused** — SQLite returns 0/1, so declare `z.number()` and keep the row type honest (`z.boolean()` stays right for an operation's *input*) |
|
|
@@ -60,10 +63,36 @@ const sql = emitTables(entities);
|
|
|
60
63
|
|
|
61
64
|
Pass `{ ifNotExists: true }` to emit `CREATE TABLE IF NOT EXISTS`.
|
|
62
65
|
|
|
66
|
+
## Not every table is keyed by `id`
|
|
67
|
+
|
|
68
|
+
`primaryKey` defaults to `['id']`, and is declared where the identity is something else:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
// the side table the design rules prescribe for extra data on an engine's entity.
|
|
72
|
+
// Its identity IS the work order's — an `id` of its own would permit two side
|
|
73
|
+
// rows for one work order, which is what the primary key exists to prevent.
|
|
74
|
+
ext: {
|
|
75
|
+
table: 'vertical_workorder_ext',
|
|
76
|
+
fields: z.object({ workorder_id: z.string(), route_note: z.string().nullable() }),
|
|
77
|
+
primaryKey: ['workorder_id'],
|
|
78
|
+
},
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
It stays separate from `key` because SQL's own distinction is the useful one: `primaryKey`
|
|
82
|
+
is identity, `key` is an additional uniqueness rule, and a table legitimately has both.
|
|
83
|
+
Column order is preserved rather than sorted — a composite primary key is also the index its
|
|
84
|
+
columns are searched by, left to right.
|
|
85
|
+
|
|
86
|
+
An entity with neither an `id` field nor a `primaryKey` is **refused**. It used to emit a
|
|
87
|
+
table with no primary key at all, silently: a production vertical had that on 15 of 63
|
|
88
|
+
tables while its own column-by-column parity check reported 63/63, because it never compared
|
|
89
|
+
primary keys ([#804](https://github.com/substrat-run/substrat/issues/804)). `journalPrimaryKeys`
|
|
90
|
+
is the reader that closes that gap, next to `journalColumns` and `journalUniques`.
|
|
91
|
+
|
|
63
92
|
## It is stricter than a hand-written schema, in one way
|
|
64
93
|
|
|
65
|
-
|
|
66
|
-
*not* imply `NOT NULL`, so `id TEXT PRIMARY KEY` accepts a NULL id:
|
|
94
|
+
The primary key becomes `TEXT PRIMARY KEY **NOT NULL**`. In SQLite a non-INTEGER primary key
|
|
95
|
+
does *not* imply `NOT NULL`, so `id TEXT PRIMARY KEY` accepts a NULL id:
|
|
67
96
|
|
|
68
97
|
```
|
|
69
98
|
hand-written id TEXT PRIMARY KEY → ACCEPTED a NULL id
|
|
@@ -71,7 +100,7 @@ emitted id TEXT PRIMARY KEY NOT NULL → rejected
|
|
|
71
100
|
```
|
|
72
101
|
|
|
73
102
|
Every hand-written `vertical_*` table in the Substrat repo had that hole. The emitter cannot
|
|
74
|
-
produce it.
|
|
103
|
+
produce it, and it refuses a nullable key column for the same reason.
|
|
75
104
|
|
|
76
105
|
## It refuses rather than guesses
|
|
77
106
|
|
package/dist/emit-sql.d.ts
CHANGED
|
@@ -6,10 +6,14 @@ export interface EmitSqlOptions {
|
|
|
6
6
|
/**
|
|
7
7
|
* `CREATE TABLE` for every declared entity, in sorted order.
|
|
8
8
|
*
|
|
9
|
-
* -
|
|
9
|
+
* - The primary key — `primaryKey` if declared, else `id` — becomes
|
|
10
|
+
* `TEXT PRIMARY KEY NOT NULL` inline when it is one column, and a table-level
|
|
11
|
+
* `PRIMARY KEY (a, b)` when it is several. The `NOT NULL` is deliberate and
|
|
10
12
|
* stricter than most hand-written schemas: in SQLite a non-INTEGER primary key
|
|
11
13
|
* does NOT imply it, so `id TEXT PRIMARY KEY` accepts a NULL id. Every
|
|
12
14
|
* `vertical_*` table written by hand in this repo has that hole.
|
|
15
|
+
* - An entity with neither is an ERROR. A table emitted with no primary key
|
|
16
|
+
* accepts duplicate rows and a column-wise parity check cannot see it (#804).
|
|
13
17
|
* - `key` becomes a `UNIQUE` constraint.
|
|
14
18
|
* - `parents` becomes a `REFERENCES` clause per parent, on `<parent>_id` when the
|
|
15
19
|
* entity declares such a column — never invented if it does not.
|
|
@@ -32,6 +36,18 @@ export interface EmittedColumn {
|
|
|
32
36
|
* a schema subtly unlike the one a fresh `CREATE TABLE` would.
|
|
33
37
|
*/
|
|
34
38
|
export declare function columnsOf<T extends Record<string, EntityDef>>(name: string, entity: EntityDef, entities: T): EmittedColumn[];
|
|
39
|
+
/**
|
|
40
|
+
* The table-level `PRIMARY KEY (a, b)`, for a composite key only.
|
|
41
|
+
*
|
|
42
|
+
* A single-column key is written inline by `columnsOf`, so this returns nothing
|
|
43
|
+
* for it — emitting both would declare the primary key twice and SQLite would
|
|
44
|
+
* refuse the table.
|
|
45
|
+
*
|
|
46
|
+
* Column order is preserved, not sorted: a composite primary key is also the
|
|
47
|
+
* index its columns are searched by, left to right, so `(customer_id, year,
|
|
48
|
+
* month)` and `(year, month, customer_id)` are different tables.
|
|
49
|
+
*/
|
|
50
|
+
export declare function primaryKeyConstraint(name: string, entity: EntityDef): string[];
|
|
35
51
|
/**
|
|
36
52
|
* The natural key, as ONE constraint over all its fields.
|
|
37
53
|
*
|
package/dist/emit-sql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit-sql.d.ts","sourceRoot":"","sources":["../src/emit-sql.ts"],"names":[],"mappings":"AAqBA,OAAO,
|
|
1
|
+
{"version":3,"file":"emit-sql.d.ts","sourceRoot":"","sources":["../src/emit-sql.ts"],"names":[],"mappings":"AAqBA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AA+HpF,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAC5D,QAAQ,EAAE,CAAC,EACX,OAAO,GAAE,cAAmB,GAC3B,MAAM,CAgBR;AAED,0FAA0F;AAC1F,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;CAC1C;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAC3D,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,CAAC,GACV,aAAa,EAAE,CAmCjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,EAAE,CAG9E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,EAAE,CAO3E"}
|
package/dist/emit-sql.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* silently — for anything reaching a migration, absent must be loud.
|
|
20
20
|
*/
|
|
21
21
|
import { z } from 'zod';
|
|
22
|
-
import { JSON_COLUMN } from '@substrat-run/contracts';
|
|
22
|
+
import { JSON_COLUMN, primaryKeyOf } from '@substrat-run/contracts';
|
|
23
23
|
/** Unwrap the wrappers Zod puts around a base type, recording nullability. */
|
|
24
24
|
function peel(schema) {
|
|
25
25
|
let s = schema;
|
|
@@ -127,10 +127,14 @@ function tableOrder(entities) {
|
|
|
127
127
|
/**
|
|
128
128
|
* `CREATE TABLE` for every declared entity, in sorted order.
|
|
129
129
|
*
|
|
130
|
-
* -
|
|
130
|
+
* - The primary key — `primaryKey` if declared, else `id` — becomes
|
|
131
|
+
* `TEXT PRIMARY KEY NOT NULL` inline when it is one column, and a table-level
|
|
132
|
+
* `PRIMARY KEY (a, b)` when it is several. The `NOT NULL` is deliberate and
|
|
131
133
|
* stricter than most hand-written schemas: in SQLite a non-INTEGER primary key
|
|
132
134
|
* does NOT imply it, so `id TEXT PRIMARY KEY` accepts a NULL id. Every
|
|
133
135
|
* `vertical_*` table written by hand in this repo has that hole.
|
|
136
|
+
* - An entity with neither is an ERROR. A table emitted with no primary key
|
|
137
|
+
* accepts duplicate rows and a column-wise parity check cannot see it (#804).
|
|
134
138
|
* - `key` becomes a `UNIQUE` constraint.
|
|
135
139
|
* - `parents` becomes a `REFERENCES` clause per parent, on `<parent>_id` when the
|
|
136
140
|
* entity declares such a column — never invented if it does not.
|
|
@@ -144,6 +148,7 @@ export function emitTables(entities, options = {}) {
|
|
|
144
148
|
continue;
|
|
145
149
|
const cols = [
|
|
146
150
|
...columnsOf(name, entity, entities).map((c) => ` ${c.ddl}`),
|
|
151
|
+
...primaryKeyConstraint(name, entity).map((k) => ` ${k}`),
|
|
147
152
|
...uniqueConstraints(name, entity).map((u) => ` ${u}`),
|
|
148
153
|
];
|
|
149
154
|
out.push(`CREATE TABLE ${exists}${entity.table} (\n${cols.join(',\n')}\n);`);
|
|
@@ -161,14 +166,24 @@ export function emitTables(entities, options = {}) {
|
|
|
161
166
|
export function columnsOf(name, entity, entities) {
|
|
162
167
|
const shape = entity.fields.shape;
|
|
163
168
|
const out = [];
|
|
169
|
+
const pk = primaryKeyOf(name, entity);
|
|
170
|
+
const inKey = new Set(pk);
|
|
164
171
|
for (const [field, schema] of Object.entries(shape)) {
|
|
165
172
|
const c = columnFor(field, schema, `${name}.${field}`);
|
|
166
|
-
if (field
|
|
167
|
-
|
|
168
|
-
|
|
173
|
+
if (inKey.has(field) && c.nullable) {
|
|
174
|
+
// A nullable primary-key column is a contradiction the database would not
|
|
175
|
+
// catch: SQLite lets a NULL into a non-INTEGER primary key, which is the
|
|
176
|
+
// very hole this emitter exists to close.
|
|
177
|
+
throw new Error(`emit-sql: ${name}.${field} is part of the primary key but is nullable — ` +
|
|
178
|
+
'a key column identifies a row, so it cannot be absent');
|
|
169
179
|
}
|
|
170
180
|
let ddl = `${c.name} ${c.type}`;
|
|
171
|
-
|
|
181
|
+
// One column: inline, which is what a hand-written schema writes and what
|
|
182
|
+
// keeps `id TEXT PRIMARY KEY NOT NULL` byte-identical. Several: a
|
|
183
|
+
// table-level constraint, the only way SQL can express it.
|
|
184
|
+
if (inKey.has(field) && pk.length === 1)
|
|
185
|
+
ddl += ' PRIMARY KEY NOT NULL';
|
|
186
|
+
else if (!c.nullable)
|
|
172
187
|
ddl += ' NOT NULL';
|
|
173
188
|
if (c.check)
|
|
174
189
|
ddl += ` ${c.check}`;
|
|
@@ -183,6 +198,21 @@ export function columnsOf(name, entity, entities) {
|
|
|
183
198
|
}
|
|
184
199
|
return out;
|
|
185
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* The table-level `PRIMARY KEY (a, b)`, for a composite key only.
|
|
203
|
+
*
|
|
204
|
+
* A single-column key is written inline by `columnsOf`, so this returns nothing
|
|
205
|
+
* for it — emitting both would declare the primary key twice and SQLite would
|
|
206
|
+
* refuse the table.
|
|
207
|
+
*
|
|
208
|
+
* Column order is preserved, not sorted: a composite primary key is also the
|
|
209
|
+
* index its columns are searched by, left to right, so `(customer_id, year,
|
|
210
|
+
* month)` and `(year, month, customer_id)` are different tables.
|
|
211
|
+
*/
|
|
212
|
+
export function primaryKeyConstraint(name, entity) {
|
|
213
|
+
const pk = primaryKeyOf(name, entity);
|
|
214
|
+
return pk.length > 1 ? [`PRIMARY KEY (${pk.join(', ')})`] : [];
|
|
215
|
+
}
|
|
186
216
|
/**
|
|
187
217
|
* The natural key, as ONE constraint over all its fields.
|
|
188
218
|
*
|
package/dist/emit-sql.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit-sql.js","sourceRoot":"","sources":["../src/emit-sql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAkB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"emit-sql.js","sourceRoot":"","sources":["../src/emit-sql.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { emitTables, columnsOf, uniqueConstraints, type EmitSqlOptions, type EmittedColumn } from './emit-sql.js';
|
|
2
|
-
export { journalColumns, journalUniques } from './journal.js';
|
|
1
|
+
export { emitTables, columnsOf, primaryKeyConstraint, uniqueConstraints, type EmitSqlOptions, type EmittedColumn, } from './emit-sql.js';
|
|
2
|
+
export { journalColumns, journalUniques, journalPrimaryKeys } from './journal.js';
|
|
3
3
|
export { planMigration, parseJournal, type Journal, type JournalEntry, type MigrationPlan, } from './plan.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EACL,aAAa,EACb,YAAY,EACZ,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { emitTables, columnsOf, uniqueConstraints } from './emit-sql.js';
|
|
2
|
-
export { journalColumns, journalUniques } from './journal.js';
|
|
1
|
+
export { emitTables, columnsOf, primaryKeyConstraint, uniqueConstraints, } from './emit-sql.js';
|
|
2
|
+
export { journalColumns, journalUniques, journalPrimaryKeys } from './journal.js';
|
|
3
3
|
export { planMigration, parseJournal, } from './plan.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EACT,oBAAoB,EACpB,iBAAiB,GAGlB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EACL,aAAa,EACb,YAAY,GAIb,MAAM,WAAW,CAAC"}
|
package/dist/journal.d.ts
CHANGED
|
@@ -34,4 +34,24 @@ export declare function journalColumns(sql: string): Map<string, Set<string>>;
|
|
|
34
34
|
* constraint written two ways compares equal.
|
|
35
35
|
*/
|
|
36
36
|
export declare function journalUniques(sql: string): Map<string, Set<string>>;
|
|
37
|
+
/**
|
|
38
|
+
* The primary key per table, read out of a journal.
|
|
39
|
+
*
|
|
40
|
+
* `journalColumns` answers "which columns exist" and `journalUniques` "which
|
|
41
|
+
* uniqueness rules"; neither says which columns *identify* a row, and that gap
|
|
42
|
+
* is what made #804 invisible. A production vertical's parity check compared
|
|
43
|
+
* names, types and nullability across 63 tables and reported 63/63 while 15 of
|
|
44
|
+
* the emitted tables had no primary key at all.
|
|
45
|
+
*
|
|
46
|
+
* Both spellings are read, because journals use both: inline
|
|
47
|
+
* (`id TEXT PRIMARY KEY NOT NULL`) for one column, and a table-level
|
|
48
|
+
* `PRIMARY KEY (a, b)` for several. A table with no primary key maps to an
|
|
49
|
+
* EMPTY array rather than being absent — "the journal never built this table"
|
|
50
|
+
* and "the journal built it without a key" are different answers, and only one
|
|
51
|
+
* of them is a bug.
|
|
52
|
+
*
|
|
53
|
+
* Order is preserved: a composite primary key is the index its columns are
|
|
54
|
+
* searched by, so `(a, b)` and `(b, a)` are not the same key.
|
|
55
|
+
*/
|
|
56
|
+
export declare function journalPrimaryKeys(sql: string): Map<string, string[]>;
|
|
37
57
|
//# sourceMappingURL=journal.d.ts.map
|
package/dist/journal.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CA4CpE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAwDpE"}
|
|
1
|
+
{"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CA4CpE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAwDpE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAyDrE"}
|
package/dist/journal.js
CHANGED
|
@@ -126,4 +126,80 @@ export function journalUniques(sql) {
|
|
|
126
126
|
}
|
|
127
127
|
return tables;
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* The primary key per table, read out of a journal.
|
|
131
|
+
*
|
|
132
|
+
* `journalColumns` answers "which columns exist" and `journalUniques` "which
|
|
133
|
+
* uniqueness rules"; neither says which columns *identify* a row, and that gap
|
|
134
|
+
* is what made #804 invisible. A production vertical's parity check compared
|
|
135
|
+
* names, types and nullability across 63 tables and reported 63/63 while 15 of
|
|
136
|
+
* the emitted tables had no primary key at all.
|
|
137
|
+
*
|
|
138
|
+
* Both spellings are read, because journals use both: inline
|
|
139
|
+
* (`id TEXT PRIMARY KEY NOT NULL`) for one column, and a table-level
|
|
140
|
+
* `PRIMARY KEY (a, b)` for several. A table with no primary key maps to an
|
|
141
|
+
* EMPTY array rather than being absent — "the journal never built this table"
|
|
142
|
+
* and "the journal built it without a key" are different answers, and only one
|
|
143
|
+
* of them is a bug.
|
|
144
|
+
*
|
|
145
|
+
* Order is preserved: a composite primary key is the index its columns are
|
|
146
|
+
* searched by, so `(a, b)` and `(b, a)` are not the same key.
|
|
147
|
+
*/
|
|
148
|
+
export function journalPrimaryKeys(sql) {
|
|
149
|
+
const tables = new Map();
|
|
150
|
+
for (const [, table, body] of sql.matchAll(/CREATE TABLE (?:IF NOT EXISTS )?([a-z_][a-z0-9_]*)\s*\(([\s\S]*?)\n\s*\);/gi)) {
|
|
151
|
+
if (!table || !body)
|
|
152
|
+
continue;
|
|
153
|
+
let key = [];
|
|
154
|
+
let depth = 0;
|
|
155
|
+
for (const raw of body.split('\n')) {
|
|
156
|
+
const line = raw.trim();
|
|
157
|
+
const atTop = depth === 0;
|
|
158
|
+
depth += (line.match(/\(/g) ?? []).length - (line.match(/\)/g) ?? []).length;
|
|
159
|
+
if (!atTop || !line || line.startsWith('--'))
|
|
160
|
+
continue;
|
|
161
|
+
// Table-level. Written as its own clause, so it wins over any inline
|
|
162
|
+
// spelling — a table cannot legally have both, and if one somehow did,
|
|
163
|
+
// the explicit list is the one a reader would believe.
|
|
164
|
+
const composite = /^(?:CONSTRAINT\s+[a-z_][a-z0-9_]*\s+)?PRIMARY\s+KEY\s*\(([^)]*)\)/i.exec(line);
|
|
165
|
+
if (composite?.[1]) {
|
|
166
|
+
key = composite[1]
|
|
167
|
+
.split(',')
|
|
168
|
+
// `PRIMARY KEY (a DESC, b COLLATE NOCASE)` — the column is the first word.
|
|
169
|
+
.map((c) => /^([a-z_][a-z0-9_]*)/i.exec(c.trim())?.[1] ?? '')
|
|
170
|
+
.filter(Boolean);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (/^(PRIMARY|FOREIGN|UNIQUE|CHECK|CONSTRAINT)\b/i.test(line))
|
|
174
|
+
continue;
|
|
175
|
+
// Inline, on the column that carries it.
|
|
176
|
+
const name = /^([a-z_][a-z0-9_]*)\b/i.exec(line)?.[1];
|
|
177
|
+
if (name && /\bPRIMARY\s+KEY\b/i.test(line) && key.length === 0)
|
|
178
|
+
key = [name];
|
|
179
|
+
}
|
|
180
|
+
tables.set(table, key);
|
|
181
|
+
}
|
|
182
|
+
// Replayed in statement order, like `journalColumns`. A rebuild renames a
|
|
183
|
+
// table onto another's name and the key travels with it; `ADD COLUMN` cannot
|
|
184
|
+
// introduce one, because SQLite refuses to add a PRIMARY KEY column.
|
|
185
|
+
for (const m of sql.matchAll(/(?:ALTER TABLE ([a-z_][a-z0-9_]*)\s+RENAME COLUMN\s+([a-z_][a-z0-9_]*)\s+TO\s+([a-z_][a-z0-9_]*))|(?:ALTER TABLE ([a-z_][a-z0-9_]*)\s+RENAME TO\s+([a-z_][a-z0-9_]*))|(?:DROP TABLE (?:IF EXISTS )?([a-z_][a-z0-9_]*))/gi)) {
|
|
186
|
+
const [, renTable, renFrom, renTo, fromTable, toTable, dropped] = m;
|
|
187
|
+
if (dropped) {
|
|
188
|
+
tables.delete(dropped);
|
|
189
|
+
}
|
|
190
|
+
else if (renTable && renFrom && renTo) {
|
|
191
|
+
const key = tables.get(renTable);
|
|
192
|
+
if (key)
|
|
193
|
+
tables.set(renTable, key.map((c) => (c === renFrom ? renTo : c)));
|
|
194
|
+
}
|
|
195
|
+
else if (fromTable && toTable) {
|
|
196
|
+
const key = tables.get(fromTable);
|
|
197
|
+
if (key) {
|
|
198
|
+
tables.delete(fromTable);
|
|
199
|
+
tables.set(toTable, key);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return tables;
|
|
204
|
+
}
|
|
129
205
|
//# sourceMappingURL=journal.js.map
|
package/dist/journal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"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"}
|
package/dist/plan.d.ts
CHANGED
package/dist/plan.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGvE,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;CAC3C;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAItE;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAC/D,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,OAAO,GACf,aAAa,CAwKf;AAED,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAkBlD"}
|
package/dist/plan.js
CHANGED
|
@@ -18,14 +18,15 @@
|
|
|
18
18
|
* the model, re-run, it renumbers.
|
|
19
19
|
*
|
|
20
20
|
* **What this refuses.** Anything that would rewrite history or lose data: a
|
|
21
|
-
* dropped table or column, a retyped column,
|
|
22
|
-
* table that may already hold rows. Those are real decisions
|
|
23
|
-
* a backfill, a `renamedFrom` declaration) and a
|
|
24
|
-
* would be guessing with somebody's data.
|
|
21
|
+
* dropped table or column, a retyped column, a moved primary key, or a required
|
|
22
|
+
* column added to a table that may already hold rows. Those are real decisions
|
|
23
|
+
* (expand/contract, a rebuild, a backfill, a `renamedFrom` declaration) and a
|
|
24
|
+
* generator that guessed at them would be guessing with somebody's data.
|
|
25
25
|
*/
|
|
26
26
|
import { z } from 'zod';
|
|
27
|
-
import { columnsOf, emitTables, uniqueConstraints } from './emit-sql.js';
|
|
28
|
-
import {
|
|
27
|
+
import { columnsOf, emitTables, primaryKeyConstraint, uniqueConstraints } from './emit-sql.js';
|
|
28
|
+
import { primaryKeyOf } from '@substrat-run/contracts';
|
|
29
|
+
import { journalColumns, journalPrimaryKeys, journalUniques } from './journal.js';
|
|
29
30
|
const pad = (n) => String(n).padStart(4, '0');
|
|
30
31
|
/**
|
|
31
32
|
* What one entry would have to say to bring the journal up to the model.
|
|
@@ -38,6 +39,7 @@ export function planMigration(entities, journal) {
|
|
|
38
39
|
const applied = journalColumns(journalSql);
|
|
39
40
|
const desired = journalColumns(emitTables(entities));
|
|
40
41
|
const appliedUniques = journalUniques(journalSql);
|
|
42
|
+
const appliedKeys = journalPrimaryKeys(journalSql);
|
|
41
43
|
// table name → the entity that owns it, so a diff can be reported in the
|
|
42
44
|
// vocabulary the model uses rather than in raw table names.
|
|
43
45
|
const owner = new Map();
|
|
@@ -65,6 +67,7 @@ export function planMigration(entities, journal) {
|
|
|
65
67
|
// the REFERENCES clause of every foreign key pointing outside it.
|
|
66
68
|
const cols = [
|
|
67
69
|
...columnsOf(o.name, o.entity, entities).map((c) => ` ${c.ddl}`),
|
|
70
|
+
...primaryKeyConstraint(o.name, o.entity).map((k) => ` ${k}`),
|
|
68
71
|
...uniqueConstraints(o.name, o.entity).map((u) => ` ${u}`),
|
|
69
72
|
];
|
|
70
73
|
statements.push(`CREATE TABLE ${table} (\n${cols.join(',\n')}\n);`);
|
|
@@ -122,6 +125,33 @@ export function planMigration(entities, journal) {
|
|
|
122
125
|
'rename from a drop-plus-add, and guessing wrong loses the data. Declare it with ' +
|
|
123
126
|
`\`renamedFrom: { <newName>: '${name}' }\` on the entity, or retire the column deliberately`);
|
|
124
127
|
}
|
|
128
|
+
// -- the primary key moved -------------------------------------------------
|
|
129
|
+
// SQLite cannot alter a primary key at all: it needs the table rebuilt,
|
|
130
|
+
// copied and renamed, which is a decision about live data rather than a
|
|
131
|
+
// diff. Refused LOUDLY for the same reason as a late UNIQUE — a schema that
|
|
132
|
+
// silently identifies rows differently than the journal does is how a
|
|
133
|
+
// duplicate gets in, and #804 is exactly that failure going unseen.
|
|
134
|
+
//
|
|
135
|
+
// Both comparisons below translate the journal's column names through any
|
|
136
|
+
// rename THIS plan is about to emit: the journal still names the old column,
|
|
137
|
+
// and SQLite rewrites keys and constraints along with it. Comparing
|
|
138
|
+
// untranslated makes a renamed key look like one the journal never had, and
|
|
139
|
+
// refuses the very change that would fix it. Built from `renames`, not from
|
|
140
|
+
// `renamedFrom`, so a spent declaration cannot translate a name the journal
|
|
141
|
+
// is not actually renaming.
|
|
142
|
+
const previousToCurrent = new Map([...renames].map(([current, previous]) => [previous, current]));
|
|
143
|
+
const wantKey = primaryKeyOf(o.name, o.entity).join(', ');
|
|
144
|
+
const haveKey = (appliedKeys.get(table) ?? []).map((c) => previousToCurrent.get(c) ?? c).join(', ');
|
|
145
|
+
if (haveKey !== wantKey) {
|
|
146
|
+
refusals.push(haveKey === ''
|
|
147
|
+
? `'${table}' exists in the journal with NO primary key, and the model identifies a row ` +
|
|
148
|
+
`by (${wantKey}) — SQLite cannot add a primary key to an existing table. Rebuild it in ` +
|
|
149
|
+
'a hand-written entry (create, copy, drop, rename), after deciding what to do with any ' +
|
|
150
|
+
'duplicate rows it already holds'
|
|
151
|
+
: `'${table}' is keyed by (${haveKey}) in the journal and by (${wantKey}) in the model — ` +
|
|
152
|
+
'SQLite cannot change a primary key in place. Rebuild the table in a hand-written ' +
|
|
153
|
+
'entry, or restore the declared key');
|
|
154
|
+
}
|
|
125
155
|
// -- a key declared after the table already exists ------------------------
|
|
126
156
|
// SQLite cannot ADD a UNIQUE constraint in place; it needs the table
|
|
127
157
|
// rebuilt, copied and renamed. That is a decision about live data, not a
|
|
@@ -133,14 +163,9 @@ export function planMigration(entities, journal) {
|
|
|
133
163
|
.map((c) => c.trim())
|
|
134
164
|
.filter(Boolean)
|
|
135
165
|
.join(', '));
|
|
136
|
-
// Translated through any rename THIS plan is about to emit: the journal
|
|
137
|
-
// still names the old column, and SQLite rewrites the constraint along with
|
|
138
|
-
// it. Comparing untranslated makes a renamed key look like one the journal
|
|
139
|
-
// never had, and refuses the very change that would fix it.
|
|
140
|
-
const toCurrent = new Map([...renames].map(([current, previous]) => [previous, current]));
|
|
141
166
|
const haveUniques = new Set([...(appliedUniques.get(table) ?? new Set())].map((c) => c
|
|
142
167
|
.split(', ')
|
|
143
|
-
.map((col) =>
|
|
168
|
+
.map((col) => previousToCurrent.get(col) ?? col)
|
|
144
169
|
.join(', ')));
|
|
145
170
|
for (const want of wantUniques) {
|
|
146
171
|
if (haveUniques.has(want))
|
package/dist/plan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../src/plan.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/model-emit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Build-time tooling over a Substrat model — DDL emitted from the entity registry, and the journal reader that holds it honest",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@substrat-run/contracts": "0.
|
|
25
|
+
"@substrat-run/contracts": "0.77.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"typescript": "^7.0.0",
|