@substrat-run/model-emit 0.4.1 → 0.5.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/LICENSE +202 -661
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/journal.d.ts +24 -27
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +45 -165
- package/dist/journal.js.map +1 -1
- package/dist/replay.d.ts +26 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +156 -0
- package/dist/replay.js.map +1 -0
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { emitTables, columnsOf, primaryKeyConstraint, uniqueConstraints, type EmitSqlOptions, type EmittedColumn, } from './emit-sql.js';
|
|
2
2
|
export { journalColumns, journalUniques, journalPrimaryKeys } from './journal.js';
|
|
3
|
+
export { readSchema, statements, type TableSchema } from './replay.js';
|
|
3
4
|
export { planMigration, parseJournal, type Journal, type JournalEntry, type MigrationPlan, } from './plan.js';
|
|
4
5
|
//# 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,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"}
|
|
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,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvE,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,5 @@
|
|
|
1
1
|
export { emitTables, columnsOf, primaryKeyConstraint, uniqueConstraints, } from './emit-sql.js';
|
|
2
2
|
export { journalColumns, journalUniques, journalPrimaryKeys } from './journal.js';
|
|
3
|
+
export { readSchema, statements } from './replay.js';
|
|
3
4
|
export { planMigration, parseJournal, } from './plan.js';
|
|
4
5
|
//# 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,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"}
|
|
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,EAAE,UAAU,EAAE,UAAU,EAAoB,MAAM,aAAa,CAAC;AACvE,OAAO,EACL,aAAa,EACb,YAAY,GAIb,MAAM,WAAW,CAAC"}
|
package/dist/journal.d.ts
CHANGED
|
@@ -1,36 +1,35 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reading a migration journal — the verification half of `emitTables`.
|
|
3
|
-
*
|
|
4
|
-
* The emitter's claim is "what this emits is what the database ends up with";
|
|
5
|
-
* this is how that gets checked. They live together because they are two halves
|
|
6
|
-
* of one statement, and a reader that drifts from its emitter checks nothing.
|
|
7
|
-
*/
|
|
8
1
|
/**
|
|
9
2
|
* Column names per table, read out of a migration journal's SQL.
|
|
10
3
|
*
|
|
11
|
-
* Three engines had hand-rolled a copy of this and the copies had already
|
|
12
|
-
*
|
|
13
|
-
* forever.
|
|
4
|
+
* Three engines had hand-rolled a copy of this and the copies had already
|
|
5
|
+
* drifted — none followed `RENAME TO`, so a journal that rebuilds a table under
|
|
6
|
+
* a temporary name would report the pre-rebuild columns forever.
|
|
14
7
|
*
|
|
15
8
|
* It exists because a registry and a journal are two descriptions of one schema
|
|
16
9
|
* until migrations are derived from the registry. Holding them to each other is
|
|
17
10
|
* what keeps that duplication safe in the meantime.
|
|
18
11
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
12
|
+
* Everything a real journal does is handled, because SQLite handles it:
|
|
13
|
+
* `ADD COLUMN`, `DROP TABLE`, `RENAME COLUMN`, and the `RENAME TO` that an
|
|
14
|
+
* append-only journal uses to rebuild a table by creating a `_new`, copying,
|
|
15
|
+
* dropping the original and renaming onto its name.
|
|
23
16
|
*/
|
|
24
17
|
export declare function journalColumns(sql: string): Map<string, Set<string>>;
|
|
25
18
|
/**
|
|
26
19
|
* UNIQUE constraints per table, read out of a journal.
|
|
27
20
|
*
|
|
28
|
-
* `journalColumns`
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
21
|
+
* `journalColumns` answers "which columns exist". But a declared `key` is a
|
|
22
|
+
* schema fact too, and adding one to an entity that already has a table is a
|
|
23
|
+
* change SQLite cannot make in place. Without this the planner reported "up to
|
|
24
|
+
* date" over a missing constraint.
|
|
25
|
+
*
|
|
26
|
+
* All three spellings count, because the database does not distinguish them:
|
|
27
|
+
* table-level `UNIQUE (a, b)`, column-level `b TEXT UNIQUE`, and
|
|
28
|
+
* `CREATE UNIQUE INDEX … ON t (b)`. A PARTIAL index (`… WHERE deleted_at IS
|
|
29
|
+
* NULL`) is excluded — it constrains a subset of the rows, so counting it would
|
|
30
|
+
* claim a guarantee the database does not make.
|
|
32
31
|
*
|
|
33
|
-
* Normalised to `a, b` (single space,
|
|
32
|
+
* Normalised to `a, b` (single space, key order preserved) so the same
|
|
34
33
|
* constraint written two ways compares equal.
|
|
35
34
|
*/
|
|
36
35
|
export declare function journalUniques(sql: string): Map<string, Set<string>>;
|
|
@@ -43,15 +42,13 @@ export declare function journalUniques(sql: string): Map<string, Set<string>>;
|
|
|
43
42
|
* names, types and nullability across 63 tables and reported 63/63 while 15 of
|
|
44
43
|
* the emitted tables had no primary key at all.
|
|
45
44
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
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.
|
|
45
|
+
* A table with no primary key maps to an EMPTY array rather than being absent —
|
|
46
|
+
* "the journal never built this table" and "the journal built it without a key"
|
|
47
|
+
* are different answers, and only one of them is a bug.
|
|
52
48
|
*
|
|
53
|
-
* Order is
|
|
54
|
-
* searched by, so `(a, b)` and `(b, a)`
|
|
49
|
+
* Order is the KEY's order, which is not always declaration order: a composite
|
|
50
|
+
* primary key is the index its columns are searched by, so `(a, b)` and `(b, a)`
|
|
51
|
+
* are not the same key.
|
|
55
52
|
*/
|
|
56
53
|
export declare function journalPrimaryKeys(sql: string): Map<string, string[]>;
|
|
57
54
|
//# 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":"
|
|
1
|
+
{"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAIpE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAIpE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAIrE"}
|
package/dist/journal.js
CHANGED
|
@@ -4,127 +4,60 @@
|
|
|
4
4
|
* The emitter's claim is "what this emits is what the database ends up with";
|
|
5
5
|
* this is how that gets checked. They live together because they are two halves
|
|
6
6
|
* of one statement, and a reader that drifts from its emitter checks nothing.
|
|
7
|
+
*
|
|
8
|
+
* All three readers are now views onto one replay (`./replay.ts`): the journal
|
|
9
|
+
* is run into an in-memory SQLite and the schema read back through `PRAGMA`.
|
|
10
|
+
* Before that they were three hand-rolled parsers over SQL text, and #807 is
|
|
11
|
+
* what that cost — the same table reformatted read as a different schema, and
|
|
12
|
+
* the three `RENAME TO` / `RENAME COLUMN` / `DROP TABLE` replay loops that used
|
|
13
|
+
* to live here, one per reader, were each a re-implementation of what the
|
|
14
|
+
* database does for free.
|
|
7
15
|
*/
|
|
16
|
+
import { readSchema } from './replay.js';
|
|
8
17
|
/**
|
|
9
18
|
* Column names per table, read out of a migration journal's SQL.
|
|
10
19
|
*
|
|
11
|
-
* Three engines had hand-rolled a copy of this and the copies had already
|
|
12
|
-
*
|
|
13
|
-
* forever.
|
|
20
|
+
* Three engines had hand-rolled a copy of this and the copies had already
|
|
21
|
+
* drifted — none followed `RENAME TO`, so a journal that rebuilds a table under
|
|
22
|
+
* a temporary name would report the pre-rebuild columns forever.
|
|
14
23
|
*
|
|
15
24
|
* It exists because a registry and a journal are two descriptions of one schema
|
|
16
25
|
* until migrations are derived from the registry. Holding them to each other is
|
|
17
26
|
* what keeps that duplication safe in the meantime.
|
|
18
27
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
28
|
+
* Everything a real journal does is handled, because SQLite handles it:
|
|
29
|
+
* `ADD COLUMN`, `DROP TABLE`, `RENAME COLUMN`, and the `RENAME TO` that an
|
|
30
|
+
* append-only journal uses to rebuild a table by creating a `_new`, copying,
|
|
31
|
+
* dropping the original and renaming onto its name.
|
|
23
32
|
*/
|
|
24
33
|
export function journalColumns(sql) {
|
|
25
|
-
const
|
|
26
|
-
for (const [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const cols = new Set();
|
|
30
|
-
let depth = 0;
|
|
31
|
-
for (const raw of body.split('\n')) {
|
|
32
|
-
const line = raw.trim();
|
|
33
|
-
const atTop = depth === 0;
|
|
34
|
-
depth += (line.match(/\(/g) ?? []).length - (line.match(/\)/g) ?? []).length;
|
|
35
|
-
if (!atTop)
|
|
36
|
-
continue;
|
|
37
|
-
if (!line || line.startsWith('--') || /^(PRIMARY|FOREIGN|UNIQUE|CHECK|CONSTRAINT)\b/i.test(line))
|
|
38
|
-
continue;
|
|
39
|
-
const name = /^([a-z_][a-z0-9_]*)\b/i.exec(line)?.[1];
|
|
40
|
-
if (name)
|
|
41
|
-
cols.add(name);
|
|
42
|
-
}
|
|
43
|
-
tables.set(table, cols);
|
|
44
|
-
}
|
|
45
|
-
// Replayed in statement order: a journal may add a column and later rename the
|
|
46
|
-
// table, or rename onto a name it has just dropped.
|
|
47
|
-
for (const m of sql.matchAll(
|
|
48
|
-
// `RENAME COLUMN` comes first: `RENAME TO` must not swallow it. Without this
|
|
49
|
-
// branch a renamed column reads as its old name forever, and a planner that
|
|
50
|
-
// derives migrations would emit the same rename on every run.
|
|
51
|
-
/(?:ALTER TABLE ([a-z_][a-z0-9_]*)\s+ADD COLUMN\s+([a-z_][a-z0-9_]*))|(?: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)) {
|
|
52
|
-
const [, addTable, addCol, renTable, renFrom, renTo, fromTable, toTable, dropped] = m;
|
|
53
|
-
if (addTable && addCol)
|
|
54
|
-
tables.get(addTable)?.add(addCol);
|
|
55
|
-
else if (dropped)
|
|
56
|
-
tables.delete(dropped);
|
|
57
|
-
else if (renTable && renFrom && renTo) {
|
|
58
|
-
const cols = tables.get(renTable);
|
|
59
|
-
if (cols?.delete(renFrom))
|
|
60
|
-
cols.add(renTo);
|
|
61
|
-
}
|
|
62
|
-
else if (fromTable && toTable) {
|
|
63
|
-
const cols = tables.get(fromTable);
|
|
64
|
-
if (cols) {
|
|
65
|
-
tables.delete(fromTable);
|
|
66
|
-
tables.set(toTable, cols);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return tables;
|
|
34
|
+
const out = new Map();
|
|
35
|
+
for (const [table, schema] of readSchema(sql))
|
|
36
|
+
out.set(table, new Set(schema.columns));
|
|
37
|
+
return out;
|
|
71
38
|
}
|
|
72
39
|
/**
|
|
73
40
|
* UNIQUE constraints per table, read out of a journal.
|
|
74
41
|
*
|
|
75
|
-
* `journalColumns`
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
42
|
+
* `journalColumns` answers "which columns exist". But a declared `key` is a
|
|
43
|
+
* schema fact too, and adding one to an entity that already has a table is a
|
|
44
|
+
* change SQLite cannot make in place. Without this the planner reported "up to
|
|
45
|
+
* date" over a missing constraint.
|
|
46
|
+
*
|
|
47
|
+
* All three spellings count, because the database does not distinguish them:
|
|
48
|
+
* table-level `UNIQUE (a, b)`, column-level `b TEXT UNIQUE`, and
|
|
49
|
+
* `CREATE UNIQUE INDEX … ON t (b)`. A PARTIAL index (`… WHERE deleted_at IS
|
|
50
|
+
* NULL`) is excluded — it constrains a subset of the rows, so counting it would
|
|
51
|
+
* claim a guarantee the database does not make.
|
|
79
52
|
*
|
|
80
|
-
* Normalised to `a, b` (single space,
|
|
53
|
+
* Normalised to `a, b` (single space, key order preserved) so the same
|
|
81
54
|
* constraint written two ways compares equal.
|
|
82
55
|
*/
|
|
83
56
|
export function journalUniques(sql) {
|
|
84
|
-
const
|
|
85
|
-
for (const [
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const found = new Set();
|
|
89
|
-
for (const [, cols] of body.matchAll(/\bUNIQUE\s*\(([^)]*)\)/gi)) {
|
|
90
|
-
if (!cols)
|
|
91
|
-
continue;
|
|
92
|
-
found.add(cols
|
|
93
|
-
.split(',')
|
|
94
|
-
.map((c) => c.trim())
|
|
95
|
-
.filter(Boolean)
|
|
96
|
-
.join(', '));
|
|
97
|
-
}
|
|
98
|
-
tables.set(table, found);
|
|
99
|
-
}
|
|
100
|
-
// Replayed in statement order, like `journalColumns`.
|
|
101
|
-
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)) {
|
|
102
|
-
const [, renTable, renFrom, renTo, fromTable, toTable, dropped] = m;
|
|
103
|
-
if (dropped) {
|
|
104
|
-
tables.delete(dropped);
|
|
105
|
-
}
|
|
106
|
-
else if (renTable && renFrom && renTo) {
|
|
107
|
-
// SQLite rewrites the constraint when a column is renamed — verified
|
|
108
|
-
// against a real database — so the reader has to as well. Missing this
|
|
109
|
-
// makes a renamed key look like a key the journal never had.
|
|
110
|
-
const cs = tables.get(renTable);
|
|
111
|
-
if (cs) {
|
|
112
|
-
tables.set(renTable, new Set([...cs].map((c) => c
|
|
113
|
-
.split(', ')
|
|
114
|
-
.map((col) => (col === renFrom ? renTo : col))
|
|
115
|
-
.join(', '))));
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
else if (fromTable && toTable) {
|
|
119
|
-
// A rebuild renames a table onto another's name; constraints travel with it.
|
|
120
|
-
const c = tables.get(fromTable);
|
|
121
|
-
if (c) {
|
|
122
|
-
tables.delete(fromTable);
|
|
123
|
-
tables.set(toTable, c);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return tables;
|
|
57
|
+
const out = new Map();
|
|
58
|
+
for (const [table, schema] of readSchema(sql))
|
|
59
|
+
out.set(table, new Set(schema.uniques));
|
|
60
|
+
return out;
|
|
128
61
|
}
|
|
129
62
|
/**
|
|
130
63
|
* The primary key per table, read out of a journal.
|
|
@@ -135,71 +68,18 @@ export function journalUniques(sql) {
|
|
|
135
68
|
* names, types and nullability across 63 tables and reported 63/63 while 15 of
|
|
136
69
|
* the emitted tables had no primary key at all.
|
|
137
70
|
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
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.
|
|
71
|
+
* A table with no primary key maps to an EMPTY array rather than being absent —
|
|
72
|
+
* "the journal never built this table" and "the journal built it without a key"
|
|
73
|
+
* are different answers, and only one of them is a bug.
|
|
144
74
|
*
|
|
145
|
-
* Order is
|
|
146
|
-
* searched by, so `(a, b)` and `(b, a)`
|
|
75
|
+
* Order is the KEY's order, which is not always declaration order: a composite
|
|
76
|
+
* primary key is the index its columns are searched by, so `(a, b)` and `(b, a)`
|
|
77
|
+
* are not the same key.
|
|
147
78
|
*/
|
|
148
79
|
export function journalPrimaryKeys(sql) {
|
|
149
|
-
const
|
|
150
|
-
for (const [
|
|
151
|
-
|
|
152
|
-
|
|
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;
|
|
80
|
+
const out = new Map();
|
|
81
|
+
for (const [table, schema] of readSchema(sql))
|
|
82
|
+
out.set(table, [...schema.primaryKey]);
|
|
83
|
+
return out;
|
|
204
84
|
}
|
|
205
85
|
//# 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":"AAAA
|
|
1
|
+
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC3C,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACvF,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC3C,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACvF,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IACxC,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IACtF,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/replay.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The journal's statements, split on the semicolons that actually end one.
|
|
3
|
+
*
|
|
4
|
+
* Quote- and comment-aware, because a `;` inside a string literal or a `--`
|
|
5
|
+
* comment ends nothing. This is the only text scanning left in the package, and
|
|
6
|
+
* it exists because the statements have to be filtered before they are run —
|
|
7
|
+
* `db.exec` would happily run the `INSERT`s too.
|
|
8
|
+
*/
|
|
9
|
+
export declare function statements(sql: string): string[];
|
|
10
|
+
export interface TableSchema {
|
|
11
|
+
/** Declaration order, as `PRAGMA table_info` reports it. */
|
|
12
|
+
readonly columns: string[];
|
|
13
|
+
/** Key order, not declaration order — `(a, b)` and `(b, a)` are different keys. Empty when the table has none. */
|
|
14
|
+
readonly primaryKey: string[];
|
|
15
|
+
/** Each constraint normalised to `a, b`. Excludes the primary key and any PARTIAL index. */
|
|
16
|
+
readonly uniques: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The schema a journal leaves behind, as SQLite sees it.
|
|
20
|
+
*
|
|
21
|
+
* Throws if a schema statement does not apply — which is a feature, not a
|
|
22
|
+
* regression. A journal that cannot be replayed is a journal that will not apply
|
|
23
|
+
* to a real scope either, and the old readers answered anyway.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readSchema(sql: string): Map<string, TableSchema>;
|
|
26
|
+
//# sourceMappingURL=replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../src/replay.ts"],"names":[],"mappings":"AAmDA;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CA4BhD;AAMD,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,kHAAkH;IAClH,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAC9B,4FAA4F;IAC5F,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;CAC5B;AAYD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CA2DhE"}
|
package/dist/replay.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The journal, read by REPLAYING it.
|
|
3
|
+
*
|
|
4
|
+
* Every reader in this package used to parse SQL with regular expressions, and
|
|
5
|
+
* every one of them was wrong in a way nobody could have predicted from reading
|
|
6
|
+
* it. #807 reported two defects; probing the same cause found five more in ten
|
|
7
|
+
* minutes — a `CREATE TABLE` on one line, a `) STRICT;` suffix, a wrapped
|
|
8
|
+
* `PRIMARY KEY (` list, a quoted `"order"` identifier, the word UNIQUE inside a
|
|
9
|
+
* comment. That is not a list of bugs, it is a shape: a regex over SQL text has
|
|
10
|
+
* no bottom, and every fix is a patch against the next spelling.
|
|
11
|
+
*
|
|
12
|
+
* So this does not read SQL. It runs it, into a throwaway in-memory database,
|
|
13
|
+
* and asks SQLite what the schema is. The answer is the one the production
|
|
14
|
+
* database would give, because it comes from the same engine — which is the
|
|
15
|
+
* whole claim `emitTables` makes and the reason a reader exists at all.
|
|
16
|
+
*
|
|
17
|
+
* **Only schema statements are replayed.** A journal's `INSERT`s do not change
|
|
18
|
+
* its schema, and skipping them is what lets a vertical's journal be read on its
|
|
19
|
+
* own: two of this repo's verticals hand data to an engine with
|
|
20
|
+
* `INSERT … SELECT` into a table that lives in the ENGINE's journal (the
|
|
21
|
+
* decision-28 extraction handoff), which no amount of replaying the vertical
|
|
22
|
+
* alone can satisfy. Foreign keys stay off — SQLite's default — so a
|
|
23
|
+
* `REFERENCES` pointing into another module's journal is created, not refused.
|
|
24
|
+
*
|
|
25
|
+
* Node-only, deliberately. This package is a devDependency in all of its
|
|
26
|
+
* dependents and no `src/` file imports it, so nothing here reaches a worker
|
|
27
|
+
* bundle or a scope; the builder runs its gates as shell commands in a
|
|
28
|
+
* container. `node:sqlite` is a builtin, so this costs no dependency.
|
|
29
|
+
*/
|
|
30
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
31
|
+
/** The quote characters SQLite accepts around an identifier or a literal. */
|
|
32
|
+
const CLOSING = { "'": "'", '"': '"', '`': '`', '[': ']' };
|
|
33
|
+
/** Index after the quoted run starting at `i`; a doubled quote is an escape. */
|
|
34
|
+
function endOfQuoted(s, i) {
|
|
35
|
+
const close = CLOSING[s[i]];
|
|
36
|
+
let j = i + 1;
|
|
37
|
+
while (j < s.length) {
|
|
38
|
+
if (s[j] === close) {
|
|
39
|
+
if (s[j + 1] === close) {
|
|
40
|
+
j += 2;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
return j + 1;
|
|
44
|
+
}
|
|
45
|
+
j++;
|
|
46
|
+
}
|
|
47
|
+
return s.length;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The journal's statements, split on the semicolons that actually end one.
|
|
51
|
+
*
|
|
52
|
+
* Quote- and comment-aware, because a `;` inside a string literal or a `--`
|
|
53
|
+
* comment ends nothing. This is the only text scanning left in the package, and
|
|
54
|
+
* it exists because the statements have to be filtered before they are run —
|
|
55
|
+
* `db.exec` would happily run the `INSERT`s too.
|
|
56
|
+
*/
|
|
57
|
+
export function statements(sql) {
|
|
58
|
+
const out = [];
|
|
59
|
+
let start = 0;
|
|
60
|
+
for (let i = 0; i < sql.length; i++) {
|
|
61
|
+
const c = sql[i];
|
|
62
|
+
if (CLOSING[c]) {
|
|
63
|
+
i = endOfQuoted(sql, i) - 1;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (c === '-' && sql[i + 1] === '-') {
|
|
67
|
+
while (i < sql.length && sql[i] !== '\n')
|
|
68
|
+
i++;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (c === '/' && sql[i + 1] === '*') {
|
|
72
|
+
i += 2;
|
|
73
|
+
while (i < sql.length && !(sql[i] === '*' && sql[i + 1] === '/'))
|
|
74
|
+
i++;
|
|
75
|
+
i++;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (c === ';') {
|
|
79
|
+
const s = sql.slice(start, i).trim();
|
|
80
|
+
if (s)
|
|
81
|
+
out.push(s);
|
|
82
|
+
start = i + 1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const last = sql.slice(start).trim();
|
|
86
|
+
if (last)
|
|
87
|
+
out.push(last);
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
/** Statements that change the schema — the only ones worth replaying. */
|
|
91
|
+
const isSchemaStatement = (s) => /^(CREATE|ALTER|DROP)\b/i.test(s.replace(/^(?:\s|--[^\n]*\n|\/\*[\s\S]*?\*\/)*/, ''));
|
|
92
|
+
/**
|
|
93
|
+
* One replay per journal string.
|
|
94
|
+
*
|
|
95
|
+
* `planMigration` asks for columns, keys and uniques off the same journal, and
|
|
96
|
+
* building three identical databases to answer three questions about one schema
|
|
97
|
+
* would be silly. Keyed on the SQL itself, which is what makes it safe: the
|
|
98
|
+
* readers are pure functions of their input, and this does not change that.
|
|
99
|
+
*/
|
|
100
|
+
const cache = new Map();
|
|
101
|
+
/**
|
|
102
|
+
* The schema a journal leaves behind, as SQLite sees it.
|
|
103
|
+
*
|
|
104
|
+
* Throws if a schema statement does not apply — which is a feature, not a
|
|
105
|
+
* regression. A journal that cannot be replayed is a journal that will not apply
|
|
106
|
+
* to a real scope either, and the old readers answered anyway.
|
|
107
|
+
*/
|
|
108
|
+
export function readSchema(sql) {
|
|
109
|
+
const hit = cache.get(sql);
|
|
110
|
+
if (hit)
|
|
111
|
+
return hit;
|
|
112
|
+
const db = new DatabaseSync(':memory:');
|
|
113
|
+
try {
|
|
114
|
+
for (const statement of statements(sql)) {
|
|
115
|
+
if (!isSchemaStatement(statement))
|
|
116
|
+
continue;
|
|
117
|
+
try {
|
|
118
|
+
db.exec(statement);
|
|
119
|
+
}
|
|
120
|
+
catch (cause) {
|
|
121
|
+
const head = statement.replace(/\s+/g, ' ').slice(0, 120);
|
|
122
|
+
throw new Error(`journal: a schema statement does not apply — ${cause.message}\n in: ${head}…\n` +
|
|
123
|
+
'The journal is replayed into SQLite to read its schema, so a statement that cannot ' +
|
|
124
|
+
'run here would not run against a scope either.', { cause });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const schema = new Map();
|
|
128
|
+
const names = db
|
|
129
|
+
.prepare(`SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name`)
|
|
130
|
+
.all();
|
|
131
|
+
for (const { name } of names) {
|
|
132
|
+
const info = db.prepare(`SELECT name FROM pragma_table_info(?)`).all(name);
|
|
133
|
+
const primaryKey = db.prepare(`SELECT name FROM pragma_table_info(?) WHERE pk > 0 ORDER BY pk`).all(name).map((r) => r.name);
|
|
134
|
+
const uniques = [];
|
|
135
|
+
const indexes = db
|
|
136
|
+
.prepare(`SELECT name, "unique" AS uniq, partial, origin FROM pragma_index_list(?)`)
|
|
137
|
+
.all(name);
|
|
138
|
+
for (const index of indexes) {
|
|
139
|
+
// `pk` is the primary key wearing an index; it has its own reader.
|
|
140
|
+
// A PARTIAL index constrains a subset of the rows, so reading it as a
|
|
141
|
+
// key would claim a guarantee the database does not make.
|
|
142
|
+
if (!index.uniq || index.partial || index.origin === 'pk')
|
|
143
|
+
continue;
|
|
144
|
+
const cols = db.prepare(`SELECT name FROM pragma_index_info(?) ORDER BY seqno`).all(index.name).map((r) => r.name);
|
|
145
|
+
uniques.push(cols.join(', '));
|
|
146
|
+
}
|
|
147
|
+
schema.set(name, { columns: info.map((c) => c.name), primaryKey, uniques });
|
|
148
|
+
}
|
|
149
|
+
cache.set(sql, schema);
|
|
150
|
+
return schema;
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
db.close();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=replay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../src/replay.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.5.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,9 +22,10 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@substrat-run/contracts": "0.
|
|
25
|
+
"@substrat-run/contracts": "0.79.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
+
"@types/node": "^22.0.0",
|
|
28
29
|
"typescript": "^7.0.0",
|
|
29
30
|
"vitest": "^3.2.7",
|
|
30
31
|
"zod": "^4.4.3"
|
|
@@ -35,6 +36,9 @@
|
|
|
35
36
|
"peerDependencies": {
|
|
36
37
|
"zod": "^4.4.0"
|
|
37
38
|
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22.5"
|
|
41
|
+
},
|
|
38
42
|
"scripts": {
|
|
39
43
|
"build": "tsc -p tsconfig.json",
|
|
40
44
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
|