@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.
- package/db.win32-x64-msvc.node +0 -0
- package/dist/BaseEntity.d.ts +40 -27
- package/dist/BaseEntity.d.ts.map +1 -1
- package/dist/BaseEntity.js +82 -81
- package/dist/BaseEntity.js.map +1 -1
- package/dist/BaseModel.d.ts +10 -0
- package/dist/BaseModel.d.ts.map +1 -1
- package/dist/BaseModel.js +10 -0
- package/dist/BaseModel.js.map +1 -1
- package/dist/BaseRepository.d.ts.map +1 -1
- package/dist/BaseRepository.js +31 -5
- package/dist/BaseRepository.js.map +1 -1
- package/dist/ConnectionManager.d.ts.map +1 -1
- package/dist/ConnectionManager.js +22 -1
- package/dist/ConnectionManager.js.map +1 -1
- package/dist/ModelQuery.d.ts +22 -1
- package/dist/ModelQuery.d.ts.map +1 -1
- package/dist/ModelQuery.js +43 -20
- package/dist/ModelQuery.js.map +1 -1
- package/dist/Transaction.d.ts +9 -0
- package/dist/Transaction.d.ts.map +1 -1
- package/dist/Transaction.js +14 -0
- package/dist/Transaction.js.map +1 -1
- package/dist/adapters/NapiDbAdapter.d.ts.map +1 -1
- package/dist/adapters/NapiDbAdapter.js +7 -0
- package/dist/adapters/NapiDbAdapter.js.map +1 -1
- package/dist/decorators/entity.d.ts +4 -0
- package/dist/decorators/entity.d.ts.map +1 -1
- package/dist/decorators/entity.js +9 -1
- package/dist/decorators/entity.js.map +1 -1
- package/dist/decorators/hooks.d.ts +28 -0
- package/dist/decorators/hooks.d.ts.map +1 -1
- package/dist/decorators/hooks.js +43 -0
- package/dist/decorators/hooks.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/query/DatabaseQueryBuilder.d.ts +24 -0
- package/dist/query/DatabaseQueryBuilder.d.ts.map +1 -1
- package/dist/query/DatabaseQueryBuilder.js +98 -3
- package/dist/query/DatabaseQueryBuilder.js.map +1 -1
- package/dist/schema/SchemaBuilder.d.ts +2 -1
- package/dist/schema/SchemaBuilder.d.ts.map +1 -1
- package/dist/schema/SchemaBuilder.js +2 -1
- package/dist/schema/SchemaBuilder.js.map +1 -1
- package/dist/schema/TableBuilder.d.ts +140 -132
- package/dist/schema/TableBuilder.d.ts.map +1 -1
- package/dist/schema/TableBuilder.js +232 -231
- package/dist/schema/TableBuilder.js.map +1 -1
- package/dist/services/db.d.ts +7 -0
- package/dist/services/db.d.ts.map +1 -1
- package/dist/services/db.js.map +1 -1
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +4 -4
- package/src/BaseEntity.ts +115 -85
- package/src/BaseModel.ts +10 -0
- package/src/BaseRepository.ts +36 -4
- package/src/ConnectionManager.ts +26 -1
- package/src/ModelQuery.ts +73 -23
- package/src/Transaction.ts +23 -0
- package/src/adapters/NapiDbAdapter.ts +7 -0
- package/src/decorators/entity.ts +13 -1
- package/src/decorators/hooks.ts +67 -0
- package/src/index.ts +8 -1
- package/src/query/DatabaseQueryBuilder.ts +118 -7
- package/src/schema/SchemaBuilder.ts +2 -1
- package/src/schema/TableBuilder.ts +331 -303
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
*
|
|
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
|
|
592
|
-
|
|
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
|
|
597
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
856
|
+
return column;
|
|
856
857
|
}
|
|
857
858
|
}
|
|
858
859
|
//# sourceMappingURL=TableBuilder.js.map
|