@syncular/typegen 0.15.26 → 0.15.28
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 +17 -5
- package/dist/sql.js +5 -1
- package/package.json +3 -3
- package/src/sql.ts +7 -1
package/README.md
CHANGED
|
@@ -142,7 +142,18 @@ After that, a deployed migration is immutable. Restore an accidentally edited
|
|
|
142
142
|
migration and express the repair in a new `NNNN_name/up.sql`; do not delete and
|
|
143
143
|
re-baseline the lock. Existing table layouts are append-only and added columns
|
|
144
144
|
must be nullable so stored payloads and every server backend can upgrade
|
|
145
|
-
safely. `
|
|
145
|
+
safely. A SQL `DEFAULT` does not make a required append safe: existing
|
|
146
|
+
Syncular row payloads remain the source of truth, and no storage backend may
|
|
147
|
+
silently invent a value for them. `baseline`, `migrations check`, and
|
|
148
|
+
`generate` therefore reject `ALTER TABLE … ADD COLUMN … NOT NULL`, including
|
|
149
|
+
one with a literal default.
|
|
150
|
+
|
|
151
|
+
Use an expand/backfill/validate rollout instead: add the trailing column as
|
|
152
|
+
nullable; deploy that schema; fill existing rows with versioned,
|
|
153
|
+
server-authoritative writes under a new idempotency key; then enforce the
|
|
154
|
+
required value in host validation. Do not tighten the synced column's
|
|
155
|
+
nullability in a later migration. `generate` appends a valid new migration to
|
|
156
|
+
the lock, while
|
|
146
157
|
`generate --check` fails until that updated lock and generated outputs are
|
|
147
158
|
committed. Drift diagnostics name the locked migration and the first affected
|
|
148
159
|
table/column without printing SQL or local paths.
|
|
@@ -316,10 +327,11 @@ duplicate or unknown-column index; unsupported virtual-table modules or FTS5
|
|
|
316
327
|
options; an FTS projection without an owner or with invalid columns;
|
|
317
328
|
trailing clauses (`STRICT`).
|
|
318
329
|
|
|
319
|
-
**`DEFAULT` literals are accepted and ignored**: typegen
|
|
320
|
-
schema *shape*; executing migrations (where defaults matter) is
|
|
321
|
-
host's job.
|
|
322
|
-
|
|
330
|
+
**`DEFAULT` literals on `CREATE TABLE` are accepted and ignored**: typegen
|
|
331
|
+
extracts the schema *shape*; executing migrations (where defaults matter) is
|
|
332
|
+
the host's job. Recording them is not needed by any emitter today. On
|
|
333
|
+
`ALTER TABLE … ADD COLUMN`, a literal default does not make a non-null append
|
|
334
|
+
safe and is rejected as described in the migration-lock section above.
|
|
323
335
|
|
|
324
336
|
## 4. Generated-module contract
|
|
325
337
|
|
package/dist/sql.js
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* - `CREATE VIRTUAL TABLE name USING fts5(cols…, content=table,
|
|
13
13
|
* [tokenize='allowlisted tokenizer'])` (RFC 0005 local projection)
|
|
14
14
|
* - column defs: `name TYPE [PRIMARY KEY] [NOT NULL] [NULL]
|
|
15
|
-
* [DEFAULT literal]`
|
|
15
|
+
* [DEFAULT literal]`; `ALTER TABLE … ADD COLUMN` is restricted to nullable
|
|
16
|
+
* columns because Syncular does not execute SQL-default backfills
|
|
16
17
|
* - `--` and C-style comments
|
|
17
18
|
*
|
|
18
19
|
* Anything else — other statements, table constraints, parameterized or
|
|
@@ -542,6 +543,9 @@ function parseAlterTable(cursor, tables) {
|
|
|
542
543
|
cursor.eatWord('COLUMN');
|
|
543
544
|
const def = parseColumnDef(cursor, false);
|
|
544
545
|
cursor.expectEnd();
|
|
546
|
+
if (!def.column.nullable) {
|
|
547
|
+
cursor.fail(`ALTER TABLE ${name}: added column ${JSON.stringify(def.column.name)} must be nullable — SQL defaults do not backfill Syncular row payloads; add the column nullable, backfill it through versioned server-authoritative writes, and enforce required values in application validation`);
|
|
548
|
+
}
|
|
545
549
|
if (table.columns.some((c) => c.name === def.column.name)) {
|
|
546
550
|
cursor.fail(`ALTER TABLE ${name}: duplicate column ${JSON.stringify(def.column.name)}`);
|
|
547
551
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/typegen",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.28",
|
|
4
4
|
"description": "Syncular schema-to-TypeScript type generator and the `syncular` CLI",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"!dist/**/*.test.d.ts"
|
|
49
49
|
],
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@syncular/core": "0.15.
|
|
52
|
-
"@syncular/server": "0.15.
|
|
51
|
+
"@syncular/core": "0.15.28",
|
|
52
|
+
"@syncular/server": "0.15.28"
|
|
53
53
|
}
|
|
54
54
|
}
|
package/src/sql.ts
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* - `CREATE VIRTUAL TABLE name USING fts5(cols…, content=table,
|
|
13
13
|
* [tokenize='allowlisted tokenizer'])` (RFC 0005 local projection)
|
|
14
14
|
* - column defs: `name TYPE [PRIMARY KEY] [NOT NULL] [NULL]
|
|
15
|
-
* [DEFAULT literal]`
|
|
15
|
+
* [DEFAULT literal]`; `ALTER TABLE … ADD COLUMN` is restricted to nullable
|
|
16
|
+
* columns because Syncular does not execute SQL-default backfills
|
|
16
17
|
* - `--` and C-style comments
|
|
17
18
|
*
|
|
18
19
|
* Anything else — other statements, table constraints, parameterized or
|
|
@@ -667,6 +668,11 @@ function parseAlterTable(
|
|
|
667
668
|
cursor.eatWord('COLUMN');
|
|
668
669
|
const def = parseColumnDef(cursor, false);
|
|
669
670
|
cursor.expectEnd();
|
|
671
|
+
if (!def.column.nullable) {
|
|
672
|
+
cursor.fail(
|
|
673
|
+
`ALTER TABLE ${name}: added column ${JSON.stringify(def.column.name)} must be nullable — SQL defaults do not backfill Syncular row payloads; add the column nullable, backfill it through versioned server-authoritative writes, and enforce required values in application validation`,
|
|
674
|
+
);
|
|
675
|
+
}
|
|
670
676
|
if (table.columns.some((c) => c.name === def.column.name)) {
|
|
671
677
|
cursor.fail(
|
|
672
678
|
`ALTER TABLE ${name}: duplicate column ${JSON.stringify(def.column.name)}`,
|