@c9up/atlas 0.2.5 → 0.2.7

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.
Files changed (73) hide show
  1. package/db.win32-x64-msvc.node +0 -0
  2. package/dist/BaseEntity.d.ts +40 -27
  3. package/dist/BaseEntity.d.ts.map +1 -1
  4. package/dist/BaseEntity.js +82 -81
  5. package/dist/BaseEntity.js.map +1 -1
  6. package/dist/BaseModel.d.ts +10 -0
  7. package/dist/BaseModel.d.ts.map +1 -1
  8. package/dist/BaseModel.js +10 -0
  9. package/dist/BaseModel.js.map +1 -1
  10. package/dist/BaseRepository.d.ts.map +1 -1
  11. package/dist/BaseRepository.js +31 -5
  12. package/dist/BaseRepository.js.map +1 -1
  13. package/dist/ConnectionManager.d.ts.map +1 -1
  14. package/dist/ConnectionManager.js +22 -1
  15. package/dist/ConnectionManager.js.map +1 -1
  16. package/dist/ModelQuery.d.ts +22 -1
  17. package/dist/ModelQuery.d.ts.map +1 -1
  18. package/dist/ModelQuery.js +43 -20
  19. package/dist/ModelQuery.js.map +1 -1
  20. package/dist/Transaction.d.ts +9 -0
  21. package/dist/Transaction.d.ts.map +1 -1
  22. package/dist/Transaction.js +14 -0
  23. package/dist/Transaction.js.map +1 -1
  24. package/dist/adapters/NapiDbAdapter.d.ts.map +1 -1
  25. package/dist/adapters/NapiDbAdapter.js +7 -0
  26. package/dist/adapters/NapiDbAdapter.js.map +1 -1
  27. package/dist/decorators/entity.d.ts +4 -0
  28. package/dist/decorators/entity.d.ts.map +1 -1
  29. package/dist/decorators/entity.js +9 -1
  30. package/dist/decorators/entity.js.map +1 -1
  31. package/dist/decorators/hooks.d.ts +28 -0
  32. package/dist/decorators/hooks.d.ts.map +1 -1
  33. package/dist/decorators/hooks.js +43 -0
  34. package/dist/decorators/hooks.js.map +1 -1
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +4 -2
  38. package/dist/index.js.map +1 -1
  39. package/dist/query/DatabaseQueryBuilder.d.ts +24 -0
  40. package/dist/query/DatabaseQueryBuilder.d.ts.map +1 -1
  41. package/dist/query/DatabaseQueryBuilder.js +98 -3
  42. package/dist/query/DatabaseQueryBuilder.js.map +1 -1
  43. package/dist/schema/SchemaBuilder.d.ts +2 -1
  44. package/dist/schema/SchemaBuilder.d.ts.map +1 -1
  45. package/dist/schema/SchemaBuilder.js +2 -1
  46. package/dist/schema/SchemaBuilder.js.map +1 -1
  47. package/dist/schema/TableBuilder.d.ts +140 -132
  48. package/dist/schema/TableBuilder.d.ts.map +1 -1
  49. package/dist/schema/TableBuilder.js +232 -231
  50. package/dist/schema/TableBuilder.js.map +1 -1
  51. package/dist/services/db.d.ts +7 -0
  52. package/dist/services/db.d.ts.map +1 -1
  53. package/dist/services/db.js.map +1 -1
  54. package/index.darwin-arm64.node +0 -0
  55. package/index.darwin-x64.node +0 -0
  56. package/index.linux-arm64-gnu.node +0 -0
  57. package/index.linux-x64-gnu.node +0 -0
  58. package/index.win32-x64-msvc.node +0 -0
  59. package/package.json +4 -4
  60. package/src/BaseEntity.ts +115 -85
  61. package/src/BaseModel.ts +10 -0
  62. package/src/BaseRepository.ts +36 -4
  63. package/src/ConnectionManager.ts +26 -1
  64. package/src/ModelQuery.ts +73 -23
  65. package/src/Transaction.ts +23 -0
  66. package/src/adapters/NapiDbAdapter.ts +7 -0
  67. package/src/decorators/entity.ts +13 -1
  68. package/src/decorators/hooks.ts +67 -0
  69. package/src/index.ts +8 -1
  70. package/src/query/DatabaseQueryBuilder.ts +118 -7
  71. package/src/schema/SchemaBuilder.ts +2 -1
  72. package/src/schema/TableBuilder.ts +331 -303
  73. package/src/services/db.ts +7 -0
@@ -45,6 +45,195 @@ export class ForeignKeyBuilder {
45
45
  return this;
46
46
  }
47
47
  }
48
+ /**
49
+ * The chainable a column-type method hands back — Knex's `ColumnBuilder`.
50
+ *
51
+ * It is bound to ITS OWN column, which is what lets `table.comment()` mean the
52
+ * table comment and `table.string('x').comment()` the column one. A builder
53
+ * flattened onto the table cannot tell those apart, and Knex has both.
54
+ */
55
+ export class ColumnBuilder {
56
+ #table;
57
+ #column;
58
+ constructor(table, column) {
59
+ this.#table = table;
60
+ this.#column = column;
61
+ }
62
+ notNullable() {
63
+ this.#column.nullable = false;
64
+ this.#table.markNullabilityTouched();
65
+ return this;
66
+ }
67
+ nullable() {
68
+ this.#column.nullable = true;
69
+ this.#table.markNullabilityTouched();
70
+ return this;
71
+ }
72
+ /**
73
+ * Set a column default. JS literals are quoted/escaped (`'x'`, `123`,
74
+ * `true` — Lucid/Knex semantics); wrap SQL expressions in {@link raw} (or
75
+ * use `Migration.now()`) to emit them verbatim.
76
+ */
77
+ defaultTo(value) {
78
+ this.#column.defaultValue = renderDefaultValue(value);
79
+ return this;
80
+ }
81
+ /** MySQL `UNSIGNED` numeric modifier (Lucid `unsigned()`). No-op on pg/sqlite. */
82
+ unsigned() {
83
+ this.#column.unsigned = true;
84
+ return this;
85
+ }
86
+ /**
87
+ * Declare the current column a foreign key.
88
+ *
89
+ * - `references('users', 'id')` — atlas form `(table, column='id')`.
90
+ * - `references('users.id')` — Lucid/Knex dotted `'table.column'` shorthand, so
91
+ * a migration copied from Lucid resolves the target the same way. A single
92
+ * argument without a dot is treated as the table name (column defaults to
93
+ * `id`), preserving the atlas one-arg behaviour.
94
+ */
95
+ references(tableOrPath, column) {
96
+ let table = tableOrPath;
97
+ let col = column ?? "id";
98
+ const dot = tableOrPath.indexOf(".");
99
+ // Dotted shorthand only when no explicit column was passed — an explicit
100
+ // second arg always wins, so `references('a.b', 'c')` stays (table 'a.b').
101
+ if (dot !== -1 && column === undefined) {
102
+ table = tableOrPath.slice(0, dot);
103
+ col = tableOrPath.slice(dot + 1);
104
+ }
105
+ this.#column.references = { table, column: col };
106
+ return this;
107
+ }
108
+ /**
109
+ * Referential action for the current column's foreign key `ON DELETE`
110
+ * (Lucid parity). Must follow {@link references}.
111
+ */
112
+ onDelete(action) {
113
+ if (this.#column.references) {
114
+ this.#column.references.onDelete = action;
115
+ }
116
+ return this;
117
+ }
118
+ /** Referential action for the current column's foreign key `ON UPDATE`. Must follow {@link references}. */
119
+ onUpdate(action) {
120
+ if (this.#column.references) {
121
+ this.#column.references.onUpdate = action;
122
+ }
123
+ return this;
124
+ }
125
+ /**
126
+ * Comment this column (Lucid/Knex column `comment()`). Inline on MySQL, a
127
+ * separate `COMMENT ON COLUMN` on Postgres, dropped on SQLite. The TABLE
128
+ * comment is `table.comment()` — the receiver tells them apart, as in Knex.
129
+ */
130
+ comment(text) {
131
+ this.#column.comment = text;
132
+ return this;
133
+ }
134
+ /** Collate this column (Lucid/Knex column `collate()`). The table collation is `table.collate()`. */
135
+ collate(collation) {
136
+ this.#column.collate = collation;
137
+ return this;
138
+ }
139
+ /**
140
+ * Place an added column first (Lucid/Knex `first()`). MySQL-only —
141
+ * Postgres and SQLite always append, and the Rust compiler raises
142
+ * `E_UNSUPPORTED` rather than dropping the instruction silently.
143
+ */
144
+ first() {
145
+ this.#column.position = { at: "first" };
146
+ return this;
147
+ }
148
+ /** Place an added column after `column` (Lucid/Knex `after()`). MySQL-only — see {@link first}. */
149
+ after(column) {
150
+ this.#column.position = { at: "after", column };
151
+ return this;
152
+ }
153
+ // ─── CHECK constraints ────────────────────────────────────
154
+ /** `CHECK (col > 0)` on this column (Lucid/Knex `checkPositive`). */
155
+ checkPositive(constraintName) {
156
+ this.#table.addColumnCheck(this.#column.name, (column) => ({ check: "positive", column }), constraintName);
157
+ return this;
158
+ }
159
+ /** `CHECK (col < 0)` on this column (Lucid/Knex `checkNegative`). */
160
+ checkNegative(constraintName) {
161
+ this.#table.addColumnCheck(this.#column.name, (column) => ({ check: "negative", column }), constraintName);
162
+ return this;
163
+ }
164
+ /** `CHECK (col IN (…))` on this column (Lucid/Knex `checkIn`). Values are quoted, never interpolated raw. */
165
+ checkIn(values, constraintName) {
166
+ this.#table.addColumnCheck(this.#column.name, (column) => ({ check: "in", column, values: [...values] }), constraintName);
167
+ return this;
168
+ }
169
+ /** `CHECK (col NOT IN (…))` on this column (Lucid/Knex `checkNotIn`). */
170
+ checkNotIn(values, constraintName) {
171
+ this.#table.addColumnCheck(this.#column.name, (column) => ({ check: "notIn", column, values: [...values] }), constraintName);
172
+ return this;
173
+ }
174
+ /**
175
+ * `CHECK (col BETWEEN lo AND hi)` on this column (Lucid/Knex
176
+ * `checkBetween`). Accepts one `[min, max]` interval or a list of them —
177
+ * several intervals are OR'd together, as in Knex.
178
+ */
179
+ checkBetween(range, constraintName) {
180
+ // A single [min, max] vs a list of intervals: the first element of a
181
+ // list-of-intervals is itself an array.
182
+ const ranges = Array.isArray(range[0])
183
+ ? range.map((r) => [...r])
184
+ : [[...range]];
185
+ this.#table.addColumnCheck(this.#column.name, (column) => ({ check: "between", column, ranges }), constraintName);
186
+ return this;
187
+ }
188
+ /** `CHECK (LENGTH(col) <op> n)` on this column (Lucid/Knex `checkLength`). The operator is allow-listed by the Rust compiler. */
189
+ checkLength(operator, length, constraintName) {
190
+ this.#table.addColumnCheck(this.#column.name, (column) => ({ check: "length", column, operator, length }), constraintName);
191
+ return this;
192
+ }
193
+ /**
194
+ * `CHECK (col ~ 'pattern')` on this column (Lucid/Knex `checkRegex`).
195
+ * Postgres spells it `~`; MySQL and SQLite use `REGEXP`.
196
+ *
197
+ * SQLite parses `REGEXP` but ships no implementation — the constraint only
198
+ * works if the connection registers a `regexp` function. Knex behaves the
199
+ * same way, so this is parity rather than a new trap, but it is worth
200
+ * knowing before you rely on it there.
201
+ */
202
+ checkRegex(pattern, constraintName) {
203
+ this.#table.addColumnCheck(this.#column.name, (column) => ({ check: "regex", column, pattern }), constraintName);
204
+ return this;
205
+ }
206
+ /** Mark this column the primary key (Lucid/Knex column `primary()`). */
207
+ primary() {
208
+ this.#column.primary = true;
209
+ return this;
210
+ }
211
+ /** Mark this column `UNIQUE` (Lucid/Knex column `unique()`). */
212
+ unique() {
213
+ this.#column.unique = true;
214
+ return this;
215
+ }
216
+ /** Index this column (Lucid/Knex column `index()`). */
217
+ index(name) {
218
+ this.#table.index(this.#column.name, name);
219
+ return this;
220
+ }
221
+ /**
222
+ * Apply this definition as a type change instead of an `ADD COLUMN`
223
+ * (Lucid/Knex `alter()`).
224
+ *
225
+ * Nullability moves only if `.nullable()` / `.notNullable()` was called
226
+ * before this — a bare `t.string('x').alter()` changes the type and leaves
227
+ * the NOT NULL constraint exactly as it is.
228
+ *
229
+ * SQLite cannot alter a column in place; the Rust compiler rejects it with
230
+ * `E_UNSUPPORTED` rather than emitting a table rebuild behind your back.
231
+ */
232
+ alter() {
233
+ this.#table.alterPendingColumn();
234
+ return this;
235
+ }
236
+ }
48
237
  /** Table builder — used inside `schema.createTable(name, callback)`. */
49
238
  export class TableBuilder {
50
239
  tableName;
@@ -88,10 +277,10 @@ export class TableBuilder {
88
277
  return this.#addIncrements(name, "bigInteger");
89
278
  }
90
279
  string(name, length = 255) {
91
- this.#addColumn(name, "string");
280
+ const column = this.#addColumn(name, "string");
92
281
  if (this.#currentColumn)
93
282
  this.#currentColumn.length = length;
94
- return this;
283
+ return column;
95
284
  }
96
285
  /**
97
286
  * Text column (Lucid/Knex `text(name, textType)`). `textType` widens the
@@ -120,12 +309,12 @@ export class TableBuilder {
120
309
  return this.#addColumn(name, "bigInteger");
121
310
  }
122
311
  decimal(name, precision = 10, scale = 2) {
123
- this.#addColumn(name, "decimal");
312
+ const column = this.#addColumn(name, "decimal");
124
313
  if (this.#currentColumn) {
125
314
  this.#currentColumn.precision = precision;
126
315
  this.#currentColumn.scale = scale;
127
316
  }
128
- return this;
317
+ return column;
129
318
  }
130
319
  /**
131
320
  * Single-precision float (Lucid `float`). `REAL` on pg/sqlite, `FLOAT` on
@@ -151,10 +340,10 @@ export class TableBuilder {
151
340
  * which has no time type to carry it).
152
341
  */
153
342
  time(name, precision) {
154
- this.#addColumn(name, "time");
343
+ const column = this.#addColumn(name, "time");
155
344
  if (this.#currentColumn)
156
345
  this.#currentColumn.precision = precision;
157
- return this;
346
+ return column;
158
347
  }
159
348
  /**
160
349
  * Timestamp column (Lucid `timestamp(name, options)`).
@@ -165,10 +354,10 @@ export class TableBuilder {
165
354
  * timestamps as TEXT).
166
355
  */
167
356
  timestamp(name, options = {}) {
168
- this.#addColumn(name, options.useTz ? "timestamptz" : "timestamp");
357
+ const column = this.#addColumn(name, options.useTz ? "timestamptz" : "timestamp");
169
358
  if (this.#currentColumn)
170
359
  this.#currentColumn.precision = options.precision;
171
- return this;
360
+ return column;
172
361
  }
173
362
  /** Alias of {@link timestamp} (Lucid `dateTime`). Use `{ useTz: true }` or {@link timestamptz} for a tz-aware column. */
174
363
  dateTime(name, options = {}) {
@@ -192,12 +381,6 @@ export class TableBuilder {
192
381
  /**
193
382
  * Binary JSON (Lucid/Knex `jsonb`). `JSONB` on pg, `JSON` on MySQL, `TEXT`
194
383
  * on SQLite.
195
- *
196
- * Deviation, named: atlas's {@link json} already maps to `JSONB` on
197
- * Postgres (it predates this method), where Lucid's `json()` maps to
198
- * `json`. Leaving `json()` alone avoids silently rewriting the physical
199
- * type of existing columns and desyncing `SchemaCheck`, so on Postgres the
200
- * two spellings coincide.
201
384
  */
202
385
  jsonb(name) {
203
386
  return this.#addColumn(name, "jsonb");
@@ -207,10 +390,10 @@ export class TableBuilder {
207
390
  * SQLite; on MySQL `length` selects `VARBINARY(n)` over `BLOB`.
208
391
  */
209
392
  binary(name, length) {
210
- this.#addColumn(name, "binary");
393
+ const column = this.#addColumn(name, "binary");
211
394
  if (this.#currentColumn)
212
395
  this.#currentColumn.length = length;
213
- return this;
396
+ return column;
214
397
  }
215
398
  /**
216
399
  * A column typed with a verbatim dialect type (Lucid/Knex `specificType`) —
@@ -223,10 +406,10 @@ export class TableBuilder {
223
406
  * argument list) and rejects anything else with `E_UNSAFE_SQL`.
224
407
  */
225
408
  specificType(name, type) {
226
- this.#addColumn(name, "specificType");
409
+ const column = this.#addColumn(name, "specificType");
227
410
  if (this.#currentColumn)
228
411
  this.#currentColumn.rawType = type;
229
- return this;
412
+ return column;
230
413
  }
231
414
  /**
232
415
  * Fixed value-set column (Lucid `enum`). MySQL renders a native `ENUM(...)`;
@@ -234,10 +417,10 @@ export class TableBuilder {
234
417
  * value set. At least one value is required.
235
418
  */
236
419
  enum(name, values) {
237
- this.#addColumn(name, "enum");
420
+ const column = this.#addColumn(name, "enum");
238
421
  if (this.#currentColumn)
239
422
  this.#currentColumn.values = values;
240
- return this;
423
+ return column;
241
424
  }
242
425
  // ─── Shortcuts ────────────────────────────────────────────
243
426
  /**
@@ -299,179 +482,21 @@ export class TableBuilder {
299
482
  */
300
483
  timestamps(useTimestamps = true, defaultToNow = true) {
301
484
  const add = (name) => {
302
- if (useTimestamps)
303
- this.timestamp(name);
304
- else
305
- this.dateTime(name);
485
+ const column = useTimestamps ? this.timestamp(name) : this.dateTime(name);
306
486
  if (defaultToNow) {
307
- this.notNullable().defaultTo(new RawSql("CURRENT_TIMESTAMP"));
487
+ column.notNullable().defaultTo(new RawSql("CURRENT_TIMESTAMP"));
308
488
  }
309
489
  };
310
490
  add("created_at");
311
491
  add("updated_at");
312
492
  return this;
313
493
  }
314
- // ─── Column modifiers ─────────────────────────────────────
315
- notNullable() {
316
- if (this.#currentColumn)
317
- this.#currentColumn.nullable = false;
318
- this.#nullabilityTouched = true;
319
- return this;
320
- }
321
- nullable() {
322
- if (this.#currentColumn)
323
- this.#currentColumn.nullable = true;
324
- this.#nullabilityTouched = true;
325
- return this;
326
- }
327
- /**
328
- * Set a column default. JS literals are quoted/escaped (`'x'`, `123`,
329
- * `true` — Lucid/Knex semantics); wrap SQL expressions in {@link raw} (or
330
- * use `Migration.now()`) to emit them verbatim.
331
- */
332
- defaultTo(value) {
333
- if (this.#currentColumn) {
334
- this.#currentColumn.defaultValue = renderDefaultValue(value);
335
- }
336
- return this;
337
- }
338
- /** MySQL `UNSIGNED` numeric modifier (Lucid `unsigned()`). No-op on pg/sqlite. */
339
- unsigned() {
340
- if (this.#currentColumn)
341
- this.#currentColumn.unsigned = true;
342
- return this;
343
- }
344
- /**
345
- * Declare the current column a foreign key.
346
- *
347
- * - `references('users', 'id')` — atlas form `(table, column='id')`.
348
- * - `references('users.id')` — Lucid/Knex dotted `'table.column'` shorthand, so
349
- * a migration copied from Lucid resolves the target the same way. A single
350
- * argument without a dot is treated as the table name (column defaults to
351
- * `id`), preserving the atlas one-arg behaviour.
352
- */
353
- references(tableOrPath, column) {
354
- let table = tableOrPath;
355
- let col = column ?? "id";
356
- const dot = tableOrPath.indexOf(".");
357
- // Dotted shorthand only when no explicit column was passed — an explicit
358
- // second arg always wins, so `references('a.b', 'c')` stays (table 'a.b').
359
- if (dot !== -1 && column === undefined) {
360
- table = tableOrPath.slice(0, dot);
361
- col = tableOrPath.slice(dot + 1);
362
- }
363
- if (this.#currentColumn) {
364
- this.#currentColumn.references = { table, column: col };
365
- }
366
- return this;
367
- }
368
- /**
369
- * Referential action for the current column's foreign key `ON DELETE`
370
- * (Lucid parity). Must follow {@link references}.
371
- */
372
- onDelete(action) {
373
- if (this.#currentColumn?.references) {
374
- this.#currentColumn.references.onDelete = action;
375
- }
376
- return this;
377
- }
378
- /** Referential action for the current column's foreign key `ON UPDATE`. Must follow {@link references}. */
379
- onUpdate(action) {
380
- if (this.#currentColumn?.references) {
381
- this.#currentColumn.references.onUpdate = action;
382
- }
383
- return this;
384
- }
385
- /**
386
- * Comment the current **column** (Lucid/Knex column `comment()`). Inline on
387
- * MySQL, a separate `COMMENT ON COLUMN` on Postgres, dropped on SQLite.
388
- *
389
- * Deviation, named: Knex's `table.comment()` is the TABLE comment, because
390
- * its column methods return a separate column builder. Atlas flattens the
391
- * column modifiers onto the table builder (`.notNullable()`, `.unique()`,
392
- * `.defaultTo()` all work this way), so `comment()` follows that same rule
393
- * and the table comment is {@link tableComment}. Resolving it by "is a
394
- * column pending?" would be exactly the kind of guessing that bites later.
395
- */
396
- comment(text) {
397
- if (this.#currentColumn)
398
- this.#currentColumn.comment = text;
399
- return this;
400
- }
401
- /** Collate the current **column** (Lucid/Knex column `collate()`). See {@link comment} for why the table form is {@link tableCollate}. */
402
- collate(collation) {
403
- if (this.#currentColumn)
404
- this.#currentColumn.collate = collation;
405
- return this;
406
- }
407
- /**
408
- * Place an added column first (Lucid/Knex `first()`). MySQL-only —
409
- * Postgres and SQLite always append, and the Rust compiler raises
410
- * `E_UNSUPPORTED` rather than dropping the instruction silently.
411
- */
412
- first() {
413
- if (this.#currentColumn)
414
- this.#currentColumn.position = { at: "first" };
415
- return this;
416
- }
417
- /** Place an added column after `column` (Lucid/Knex `after()`). MySQL-only — see {@link first}. */
418
- after(column) {
419
- if (this.#currentColumn) {
420
- this.#currentColumn.position = { at: "after", column };
421
- }
422
- return this;
423
- }
424
494
  // ─── CHECK constraints ────────────────────────────────────
425
- /** `CHECK (col > 0)` on the current column (Lucid/Knex `checkPositive`). */
426
- checkPositive(constraintName) {
427
- return this.#addCheck((column) => ({ check: "positive", column }), constraintName);
428
- }
429
- /** `CHECK (col < 0)` on the current column (Lucid/Knex `checkNegative`). */
430
- checkNegative(constraintName) {
431
- return this.#addCheck((column) => ({ check: "negative", column }), constraintName);
432
- }
433
- /** `CHECK (col IN (…))` on the current column (Lucid/Knex `checkIn`). Values are quoted, never interpolated raw. */
434
- checkIn(values, constraintName) {
435
- return this.#addCheck((column) => ({ check: "in", column, values: [...values] }), constraintName);
436
- }
437
- /** `CHECK (col NOT IN (…))` on the current column (Lucid/Knex `checkNotIn`). */
438
- checkNotIn(values, constraintName) {
439
- return this.#addCheck((column) => ({ check: "notIn", column, values: [...values] }), constraintName);
440
- }
441
- /**
442
- * `CHECK (col BETWEEN lo AND hi)` on the current column (Lucid/Knex
443
- * `checkBetween`). Accepts one `[min, max]` interval or a list of them —
444
- * several intervals are OR'd together, as in Knex.
445
- */
446
- checkBetween(range, constraintName) {
447
- // A single [min, max] vs a list of intervals: the first element of a
448
- // list-of-intervals is itself an array.
449
- const ranges = Array.isArray(range[0])
450
- ? range.map((r) => [...r])
451
- : [[...range]];
452
- return this.#addCheck((column) => ({ check: "between", column, ranges }), constraintName);
453
- }
454
- /** `CHECK (LENGTH(col) <op> n)` on the current column (Lucid/Knex `checkLength`). The operator is allow-listed by the Rust compiler. */
455
- checkLength(operator, length, constraintName) {
456
- return this.#addCheck((column) => ({ check: "length", column, operator, length }), constraintName);
457
- }
458
- /**
459
- * `CHECK (col ~ 'pattern')` on the current column (Lucid/Knex `checkRegex`).
460
- * Postgres spells it `~`; MySQL and SQLite use `REGEXP`.
461
- *
462
- * SQLite parses `REGEXP` but ships no implementation — the constraint only
463
- * works if the connection registers a `regexp` function. Knex behaves the
464
- * same way, so this is parity rather than a new trap, but it is worth
465
- * knowing before you rely on it there.
466
- */
467
- checkRegex(pattern, constraintName) {
468
- return this.#addCheck((column) => ({ check: "regex", column, pattern }), constraintName);
469
- }
470
495
  /**
471
496
  * A free-form `CHECK (predicate)` (Lucid/Knex `check`). The predicate is
472
497
  * emitted verbatim — exactly as trusted as {@link Schema.raw}, so never
473
- * build it from user input. Prefer the typed `check*` helpers, which are
474
- * safe by construction.
498
+ * build it from user input. Prefer the typed `check*` helpers on the column
499
+ * builder, which are safe by construction.
475
500
  */
476
501
  check(predicate, constraintName) {
477
502
  this.#pushConstraint({
@@ -490,17 +515,8 @@ export class TableBuilder {
490
515
  return this;
491
516
  }
492
517
  // ─── Table-level constraints ──────────────────────────────
493
- /**
494
- * With no argument, mark the current column as the primary key (the
495
- * existing column modifier). With a column list, declare a composite
496
- * `PRIMARY KEY (…)` table constraint (Lucid/Knex `primary([...])`).
497
- */
518
+ /** Composite `PRIMARY KEY (…)` table constraint (Lucid/Knex `primary([...])`). */
498
519
  primary(columns, constraintName) {
499
- if (columns === undefined) {
500
- if (this.#currentColumn)
501
- this.#currentColumn.primary = true;
502
- return this;
503
- }
504
520
  this.#pushConstraint({
505
521
  constraint: "primary",
506
522
  name: constraintName,
@@ -509,19 +525,12 @@ export class TableBuilder {
509
525
  return this;
510
526
  }
511
527
  /**
512
- * With no argument, mark the current column `UNIQUE` (the existing column
513
- * modifier). With a column list, declare a composite `UNIQUE (…)` table
514
- * constraint (Lucid/Knex `unique([...])`).
528
+ * Composite `UNIQUE (…)` table constraint (Lucid/Knex `unique([...])`).
515
529
  *
516
530
  * Note this is a real constraint, unlike {@link uniqueIndex}, which creates
517
531
  * a separate `CREATE UNIQUE INDEX`.
518
532
  */
519
533
  unique(columns, constraintName) {
520
- if (columns === undefined) {
521
- if (this.#currentColumn)
522
- this.#currentColumn.unique = true;
523
- return this;
524
- }
525
534
  this.#pushConstraint({
526
535
  constraint: "unique",
527
536
  name: constraintName ?? this.#constraintName(columns, "unique"),
@@ -588,13 +597,13 @@ export class TableBuilder {
588
597
  this.#options.charset = name;
589
598
  return this;
590
599
  }
591
- /** MySQL default collation for the table. Named `tableCollate` because {@link collate} is the column modifier — see {@link comment}. */
592
- tableCollate(name) {
600
+ /** MySQL default collation for the table (Lucid/Knex `collate`). The column form is `table.<type>(…).collate()`. */
601
+ collate(name) {
593
602
  this.#options.collate = name;
594
603
  return this;
595
604
  }
596
- /** Table comment. Named `tableComment` because {@link comment} is the column modifier — see there for why. */
597
- tableComment(text) {
605
+ /** Table comment (Lucid/Knex `comment`). The column form is `table.<type>(…).comment()`. */
606
+ comment(text) {
598
607
  this.#options.comment = text;
599
608
  return this;
600
609
  }
@@ -620,16 +629,9 @@ export class TableBuilder {
620
629
  // ─── ALTER TABLE operations ───────────────────────────────
621
630
  /**
622
631
  * Apply the pending column definition as a type change instead of an
623
- * `ADD COLUMN` (Lucid/Knex `alter()`). Must follow a column-type method.
624
- *
625
- * Nullability moves only if `.nullable()` / `.notNullable()` was called
626
- * before this — a bare `t.string('x').alter()` changes the type and leaves
627
- * the NOT NULL constraint exactly as it is.
628
- *
629
- * SQLite cannot alter a column in place; the Rust compiler rejects it with
630
- * `E_UNSUPPORTED` rather than emitting a table rebuild behind your back.
632
+ * @internal Backs `ColumnBuilder.alter()`.
631
633
  */
632
- alter() {
634
+ alterPendingColumn() {
633
635
  this.#assertAlterMode("alter()");
634
636
  const pending = this.#currentOp;
635
637
  if (!pending) {
@@ -646,7 +648,18 @@ export class TableBuilder {
646
648
  this.#operations[this.#operations.indexOf(pending)] = converted;
647
649
  this.#currentOp = converted;
648
650
  }
649
- return this;
651
+ }
652
+ /** @internal Backs `ColumnBuilder.nullable()` / `.notNullable()`. */
653
+ markNullabilityTouched() {
654
+ this.#nullabilityTouched = true;
655
+ }
656
+ /** @internal Backs the `ColumnBuilder.check*()` helpers, for a named column. */
657
+ addColumnCheck(column, build, constraintName) {
658
+ this.#pushConstraint({
659
+ constraint: "check",
660
+ name: constraintName,
661
+ expr: build(column),
662
+ });
650
663
  }
651
664
  /** Drop a column (Lucid/Knex `dropColumn`). */
652
665
  dropColumn(name) {
@@ -782,18 +795,6 @@ export class TableBuilder {
782
795
  }
783
796
  }
784
797
  /** Build a CHECK against the pending column. */
785
- #addCheck(build, constraintName) {
786
- const column = this.#currentColumn?.name;
787
- if (!column) {
788
- throw new Error("E_CHECK_MISUSE: a check* helper must follow a column definition, e.g. table.integer('qty').checkPositive()");
789
- }
790
- this.#pushConstraint({
791
- constraint: "check",
792
- name: constraintName,
793
- expr: build(column),
794
- });
795
- return this;
796
- }
797
798
  /**
798
799
  * Default constraint name, following Knex's `<table>_<columns>_<suffix>`
799
800
  * convention so `unique([...])` and `dropUnique([...])` agree without the
@@ -835,24 +836,24 @@ export class TableBuilder {
835
836
  this.#operations.push(op);
836
837
  this.#currentOp = op;
837
838
  }
838
- return this;
839
+ return new ColumnBuilder(this, col);
839
840
  }
840
841
  #addFloat(name, type, precision, scale) {
841
- this.#addColumn(name, type);
842
+ const column = this.#addColumn(name, type);
842
843
  if (this.#currentColumn) {
843
844
  this.#currentColumn.precision = precision;
844
845
  this.#currentColumn.scale = scale;
845
846
  }
846
- return this;
847
+ return column;
847
848
  }
848
849
  #addIncrements(name, type) {
849
- this.#addColumn(name, type);
850
+ const column = this.#addColumn(name, type);
850
851
  if (this.#currentColumn) {
851
852
  this.#currentColumn.autoIncrement = true;
852
853
  this.#currentColumn.primary = true;
853
854
  this.#currentColumn.nullable = false;
854
855
  }
855
- return this;
856
+ return column;
856
857
  }
857
858
  }
858
859
  //# sourceMappingURL=TableBuilder.js.map