@c9up/atlas 0.1.3 → 0.1.5
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.darwin-arm64.node +0 -0
- package/db.darwin-x64.node +0 -0
- package/db.linux-arm64-gnu.node +0 -0
- package/db.linux-x64-gnu.node +0 -0
- package/db.win32-x64-msvc.node +0 -0
- package/dist/AtlasProvider.d.ts +106 -0
- package/dist/AtlasProvider.d.ts.map +1 -0
- package/dist/AtlasProvider.js +190 -0
- package/dist/AtlasProvider.js.map +1 -0
- package/dist/BaseEntity.d.ts +255 -0
- package/dist/BaseEntity.d.ts.map +1 -0
- package/dist/BaseEntity.js +420 -0
- package/dist/BaseEntity.js.map +1 -0
- package/dist/BaseRepository.d.ts +175 -0
- package/dist/BaseRepository.d.ts.map +1 -0
- package/dist/BaseRepository.js +1451 -0
- package/dist/BaseRepository.js.map +1 -0
- package/dist/ModelQuery.d.ts +338 -0
- package/dist/ModelQuery.d.ts.map +1 -0
- package/dist/ModelQuery.js +1598 -0
- package/dist/ModelQuery.js.map +1 -0
- package/dist/Transaction.d.ts +15 -0
- package/dist/Transaction.d.ts.map +1 -0
- package/dist/Transaction.js +67 -0
- package/dist/Transaction.js.map +1 -0
- package/dist/adapters/NapiDbAdapter.d.ts +34 -0
- package/dist/adapters/NapiDbAdapter.d.ts.map +1 -0
- package/dist/adapters/NapiDbAdapter.js +96 -0
- package/dist/adapters/NapiDbAdapter.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -0
- package/dist/configure.d.ts +10 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +25 -0
- package/dist/configure.js.map +1 -0
- package/dist/decorators/entity.d.ts +235 -0
- package/dist/decorators/entity.d.ts.map +1 -0
- package/dist/decorators/entity.js +264 -0
- package/dist/decorators/entity.js.map +1 -0
- package/dist/decorators/hooks.d.ts +70 -0
- package/dist/decorators/hooks.d.ts.map +1 -0
- package/dist/decorators/hooks.js +107 -0
- package/dist/decorators/hooks.js.map +1 -0
- package/dist/decorators/scope.d.ts +35 -0
- package/dist/decorators/scope.d.ts.map +1 -0
- package/dist/decorators/scope.js +29 -0
- package/dist/decorators/scope.js.map +1 -0
- package/dist/errors.d.ts +54 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +82 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/naming/NamingStrategy.d.ts +52 -0
- package/dist/naming/NamingStrategy.d.ts.map +1 -0
- package/dist/naming/NamingStrategy.js +65 -0
- package/dist/naming/NamingStrategy.js.map +1 -0
- package/dist/query/QueryBuilder.d.ts +95 -0
- package/dist/query/QueryBuilder.d.ts.map +1 -0
- package/dist/query/QueryBuilder.js +310 -0
- package/dist/query/QueryBuilder.js.map +1 -0
- package/dist/query/native.d.ts +18 -0
- package/dist/query/native.d.ts.map +1 -0
- package/dist/query/native.js +49 -0
- package/dist/query/native.js.map +1 -0
- package/dist/schema/Migration.d.ts +55 -0
- package/dist/schema/Migration.d.ts.map +1 -0
- package/dist/schema/Migration.js +68 -0
- package/dist/schema/Migration.js.map +1 -0
- package/dist/schema/MigrationRunner.d.ts +115 -0
- package/dist/schema/MigrationRunner.d.ts.map +1 -0
- package/dist/schema/MigrationRunner.js +406 -0
- package/dist/schema/MigrationRunner.js.map +1 -0
- package/dist/schema/Schema.d.ts +22 -0
- package/dist/schema/Schema.d.ts.map +1 -0
- package/dist/schema/Schema.js +51 -0
- package/dist/schema/Schema.js.map +1 -0
- package/dist/schema/SchemaBuilder.d.ts +14 -0
- package/dist/schema/SchemaBuilder.d.ts.map +1 -0
- package/dist/schema/SchemaBuilder.js +13 -0
- package/dist/schema/SchemaBuilder.js.map +1 -0
- package/dist/schema/Seeder.d.ts +54 -0
- package/dist/schema/Seeder.d.ts.map +1 -0
- package/dist/schema/Seeder.js +89 -0
- package/dist/schema/Seeder.js.map +1 -0
- package/dist/schema/TableBuilder.d.ts +95 -0
- package/dist/schema/TableBuilder.d.ts.map +1 -0
- package/dist/schema/TableBuilder.js +234 -0
- package/dist/schema/TableBuilder.js.map +1 -0
- package/dist/schema/types.d.ts +30 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +19 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/services/db.d.ts +22 -0
- package/dist/services/db.d.ts.map +1 -0
- package/dist/services/db.js +37 -0
- package/dist/services/db.js.map +1 -0
- package/dist/testing/DatabaseCleanup.d.ts +19 -0
- package/dist/testing/DatabaseCleanup.d.ts.map +1 -0
- package/dist/testing/DatabaseCleanup.js +39 -0
- package/dist/testing/DatabaseCleanup.js.map +1 -0
- package/dist/testing/Factory.d.ts +59 -0
- package/dist/testing/Factory.d.ts.map +1 -0
- package/dist/testing/Factory.js +105 -0
- package/dist/testing/Factory.js.map +1 -0
- package/dist/testing/TestDatabase.d.ts +25 -0
- package/dist/testing/TestDatabase.d.ts.map +1 -0
- package/dist/testing/TestDatabase.js +52 -0
- package/dist/testing/TestDatabase.js.map +1 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +4 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/utils/casing.d.ts +5 -0
- package/dist/utils/casing.d.ts.map +1 -0
- package/dist/utils/casing.js +9 -0
- package/dist/utils/casing.js.map +1 -0
- package/dist/utils/dialectFromUrl.d.ts +10 -0
- package/dist/utils/dialectFromUrl.d.ts.map +1 -0
- package/dist/utils/dialectFromUrl.js +8 -0
- package/dist/utils/dialectFromUrl.js.map +1 -0
- package/dist/utils/identifier.d.ts +19 -0
- package/dist/utils/identifier.d.ts.map +1 -0
- package/dist/utils/identifier.js +27 -0
- package/dist/utils/identifier.js.map +1 -0
- package/dist/utils/safePath.d.ts +22 -0
- package/dist/utils/safePath.d.ts.map +1 -0
- package/dist/utils/safePath.js +46 -0
- package/dist/utils/safePath.js.map +1 -0
- package/dist/utils/transactionBrand.d.ts +5 -0
- package/dist/utils/transactionBrand.d.ts.map +1 -0
- package/dist/utils/transactionBrand.js +5 -0
- package/dist/utils/transactionBrand.js.map +1 -0
- 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 +1 -1
- package/src/AtlasProvider.ts +2 -2
- package/src/BaseRepository.ts +73 -11
- package/src/adapters/NapiDbAdapter.ts +1 -1
- package/src/schema/MigrationRunner.ts +16 -12
- package/src/schema/TableBuilder.ts +26 -0
- package/src/schema/types.ts +2 -0
- package/src/testing/DatabaseCleanup.ts +6 -7
package/src/BaseRepository.ts
CHANGED
|
@@ -120,6 +120,39 @@ export interface DatabaseConnection {
|
|
|
120
120
|
|
|
121
121
|
// ─── Repository ─────────────────────────────────────────────
|
|
122
122
|
|
|
123
|
+
/** Logical column types Postgres won't coerce from a text-bound param. */
|
|
124
|
+
const POSTGRES_CAST_TYPES = new Set([
|
|
125
|
+
"timestamp",
|
|
126
|
+
"datetime",
|
|
127
|
+
"date",
|
|
128
|
+
"time",
|
|
129
|
+
"uuid",
|
|
130
|
+
"json",
|
|
131
|
+
"jsonb",
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Snake column → logical type for params needing a Postgres `$N::<type>` cast.
|
|
136
|
+
* sqlx binds JS strings as `text`; Postgres won't implicitly coerce that to
|
|
137
|
+
* timestamp/uuid/date. The Rust compiler applies these on Postgres only.
|
|
138
|
+
*/
|
|
139
|
+
function computeCastTypes(
|
|
140
|
+
entityClass: Parameters<typeof getColumnMetadata>[0],
|
|
141
|
+
): Record<string, string> {
|
|
142
|
+
const out: Record<string, string> = {};
|
|
143
|
+
for (const col of getColumnMetadata(entityClass)) {
|
|
144
|
+
const t = col.type?.toLowerCase();
|
|
145
|
+
if (t && POSTGRES_CAST_TYPES.has(t)) {
|
|
146
|
+
out[camelToSnake(col.propertyKey)] = t;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// A uuid-strategy primary key is generated app-side as a string.
|
|
150
|
+
if (getPrimaryKeyGenerator(entityClass) === "uuid") {
|
|
151
|
+
out[camelToSnake(getPrimaryKey(entityClass) ?? "id")] ??= "uuid";
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
|
|
123
156
|
export class BaseRepository<T extends BaseEntity> {
|
|
124
157
|
#entityClass: EntityConstructor<T>;
|
|
125
158
|
#tableName: string;
|
|
@@ -130,6 +163,8 @@ export class BaseRepository<T extends BaseEntity> {
|
|
|
130
163
|
#validColumns: Set<string>;
|
|
131
164
|
#columnMap: Map<string, string>; // camelCase → snake_case (cached)
|
|
132
165
|
#dateColumns: Record<string, DateColumnConfig>;
|
|
166
|
+
/** Snake column → logical type for params needing a Postgres `::cast`. */
|
|
167
|
+
#castTypes: Record<string, string>;
|
|
133
168
|
/**
|
|
134
169
|
* Per-property `prepare` (model → DB) callbacks lifted directly from
|
|
135
170
|
* `@Column({ prepare })` metadata. Keyed by camelCase `propertyKey`.
|
|
@@ -214,6 +249,10 @@ export class BaseRepository<T extends BaseEntity> {
|
|
|
214
249
|
this.#validColumns.add(this.#primaryKey);
|
|
215
250
|
this.#validColumns.add(camelToSnake(this.#primaryKey));
|
|
216
251
|
this.#columnMap.set(this.#primaryKey, camelToSnake(this.#primaryKey));
|
|
252
|
+
|
|
253
|
+
// Postgres cast hints: sqlx binds JS strings as `text`, which Postgres
|
|
254
|
+
// won't coerce to timestamp/uuid/date. See `computeCastTypes`.
|
|
255
|
+
this.#castTypes = computeCastTypes(entityClass);
|
|
217
256
|
}
|
|
218
257
|
|
|
219
258
|
// ─── Column validation ────────────────────────────────────
|
|
@@ -470,6 +509,7 @@ export class BaseRepository<T extends BaseEntity> {
|
|
|
470
509
|
kind: "insert",
|
|
471
510
|
table: this.#tableName,
|
|
472
511
|
rows: specRows,
|
|
512
|
+
casts: this.#castTypes,
|
|
473
513
|
returning: [
|
|
474
514
|
camelToSnake(this.#primaryKey),
|
|
475
515
|
...this.#columns.map((c) => camelToSnake(c)),
|
|
@@ -549,6 +589,7 @@ export class BaseRepository<T extends BaseEntity> {
|
|
|
549
589
|
rows,
|
|
550
590
|
conflictColumns: conflictColumns.map((c) => this.#resolveColumn(c)),
|
|
551
591
|
updateColumns: updateColumns.map((c) => this.#resolveColumn(c)),
|
|
592
|
+
casts: this.#castTypes,
|
|
552
593
|
};
|
|
553
594
|
const compiled = compileStatementNative(spec, this.#dialect);
|
|
554
595
|
const result = await this.#db.execute(
|
|
@@ -860,7 +901,13 @@ export class BaseRepository<T extends BaseEntity> {
|
|
|
860
901
|
): Promise<void> {
|
|
861
902
|
if (set.length === 0) return;
|
|
862
903
|
const compiled = compileStatementNative(
|
|
863
|
-
{
|
|
904
|
+
{
|
|
905
|
+
kind: "update",
|
|
906
|
+
table: this.#tableName,
|
|
907
|
+
set,
|
|
908
|
+
wheres,
|
|
909
|
+
casts: this.#castTypes,
|
|
910
|
+
},
|
|
864
911
|
this.#dialect,
|
|
865
912
|
);
|
|
866
913
|
await this.#db.execute(compiled.statements[0], compiled.params);
|
|
@@ -880,12 +927,18 @@ export class BaseRepository<T extends BaseEntity> {
|
|
|
880
927
|
kind: "insert",
|
|
881
928
|
table: this.#tableName,
|
|
882
929
|
values,
|
|
930
|
+
casts: this.#castTypes,
|
|
883
931
|
returning: [
|
|
884
932
|
camelToSnake(this.#primaryKey),
|
|
885
933
|
...this.#columns.map((c) => camelToSnake(c)),
|
|
886
934
|
],
|
|
887
935
|
}
|
|
888
|
-
: {
|
|
936
|
+
: {
|
|
937
|
+
kind: "insert",
|
|
938
|
+
table: this.#tableName,
|
|
939
|
+
values,
|
|
940
|
+
casts: this.#castTypes,
|
|
941
|
+
};
|
|
889
942
|
const compiled = compileStatementNative(spec, this.#dialect);
|
|
890
943
|
if (supportsReturning) {
|
|
891
944
|
const rows = await this.#db.query<Row>(
|
|
@@ -1325,14 +1378,6 @@ export class BaseRepository<T extends BaseEntity> {
|
|
|
1325
1378
|
const tsConfig = pivot.pivotTimestamps;
|
|
1326
1379
|
const pivotAdapters = pivot.pivotColumnAdapters;
|
|
1327
1380
|
const dialect = this.#dialect;
|
|
1328
|
-
// Validated quote: allow only `[A-Za-z0-9_]` so a malicious metadata
|
|
1329
|
-
// value never breaks out of the identifier. Anything else throws.
|
|
1330
|
-
const quote = (name: string): string => {
|
|
1331
|
-
if (!/^[A-Za-z0-9_]+$/.test(name)) {
|
|
1332
|
-
throw new Error(`Unsafe identifier in pivot metadata: '${name}'`);
|
|
1333
|
-
}
|
|
1334
|
-
return dialect === "mysql" ? `\`${name}\`` : `"${name}"`;
|
|
1335
|
-
};
|
|
1336
1381
|
|
|
1337
1382
|
/**
|
|
1338
1383
|
* Resolve pivot timestamp column names from the decorator config.
|
|
@@ -1496,7 +1541,24 @@ export class BaseRepository<T extends BaseEntity> {
|
|
|
1496
1541
|
for (const [k, v] of Object.entries(ts)) pairs.push([k, v]);
|
|
1497
1542
|
return pairs;
|
|
1498
1543
|
});
|
|
1499
|
-
|
|
1544
|
+
// Postgres casts for the pivot row: the two FK columns reference the
|
|
1545
|
+
// parent / related PK types (often uuid), and pivot timestamps are
|
|
1546
|
+
// bound strings — all need `$N::<type>` on Postgres.
|
|
1547
|
+
const pivotCasts: Record<string, string> = {};
|
|
1548
|
+
const parentPkCast = this.#castTypes[camelToSnake(this.#primaryKey)];
|
|
1549
|
+
if (parentPkCast) pivotCasts[pivotFk] = parentPkCast;
|
|
1550
|
+
const relatedPkCast =
|
|
1551
|
+
computeCastTypes(relatedClass)[
|
|
1552
|
+
camelToSnake(getPrimaryKey(relatedClass) ?? "id")
|
|
1553
|
+
];
|
|
1554
|
+
if (relatedPkCast) pivotCasts[pivotOther] = relatedPkCast;
|
|
1555
|
+
for (const k of Object.keys(ts)) pivotCasts[k] = "timestamp";
|
|
1556
|
+
const spec = {
|
|
1557
|
+
kind: "insert",
|
|
1558
|
+
table: pivotTable,
|
|
1559
|
+
rows: rowPairs,
|
|
1560
|
+
casts: pivotCasts,
|
|
1561
|
+
};
|
|
1500
1562
|
const compiled = compileStatementNative(spec, dialect);
|
|
1501
1563
|
await db.execute(compiled.statements[0], compiled.params);
|
|
1502
1564
|
};
|
|
@@ -22,7 +22,7 @@ export interface AsyncDatabaseConnection {
|
|
|
22
22
|
/**
|
|
23
23
|
* Run every statement in `batch` atomically inside a single sqlx transaction.
|
|
24
24
|
* Either every statement commits or none do — used by MigrationRunner to
|
|
25
|
-
* wrap `up()` / `down()` SQL together with the `
|
|
25
|
+
* wrap `up()` / `down()` SQL together with the `ream_migrations` bookkeeping.
|
|
26
26
|
*/
|
|
27
27
|
runInTransaction(batch: readonly BatchStatement[]): Promise<number>;
|
|
28
28
|
close(): Promise<void>;
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "../utils/safePath.js";
|
|
17
17
|
import type { Migration } from "./Migration.js";
|
|
18
18
|
|
|
19
|
-
const DEFAULT_TABLE = "
|
|
19
|
+
const DEFAULT_TABLE = "ream_migrations";
|
|
20
20
|
const TABLE_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
21
21
|
|
|
22
22
|
function validateTrackingTableName(name: string): string {
|
|
@@ -99,26 +99,26 @@ export class MigrationRunner {
|
|
|
99
99
|
* @param options.migrationsDir Directory containing migration files. Defaults to `database/migrations`.
|
|
100
100
|
* @param options.dialect SQL dialect of the adapter. Defaults to `sqlite`.
|
|
101
101
|
* @param options.tableName Custom name for the migrations tracking table.
|
|
102
|
-
* Defaults to `"
|
|
102
|
+
* Defaults to `"ream_migrations"`. Must match `/^[A-Za-z_][A-Za-z0-9_]*$/` —
|
|
103
103
|
* throws `AtlasError("MIGRATION_INVALID_TABLE_NAME")` synchronously otherwise.
|
|
104
104
|
*
|
|
105
105
|
* Cleanup coupling: `DatabaseCleanup.truncateAll` (`src/testing/DatabaseCleanup.ts`)
|
|
106
|
-
* skips tables whose name starts with
|
|
107
|
-
* The default `"
|
|
108
|
-
* prefix (e.g. `"schema_versions"`) opts the tracking table
|
|
109
|
-
* protection — `truncateAll` will wipe it alongside user tables,
|
|
110
|
-
* re-`init()` and replay of every migration on next test run.
|
|
106
|
+
* skips tables whose name starts with `ream_` (via `LIKE 'ream\_%' ESCAPE '\'`).
|
|
107
|
+
* The default `"ream_migrations"` is therefore auto-protected. Choosing a name
|
|
108
|
+
* without the `ream_` prefix (e.g. `"schema_versions"`) opts the tracking table
|
|
109
|
+
* out of that protection — `truncateAll` will wipe it alongside user tables,
|
|
110
|
+
* forcing a re-`init()` and replay of every migration on next test run.
|
|
111
111
|
*
|
|
112
112
|
* Rename caveat: `init()` emits `CREATE TABLE IF NOT EXISTS <tableName>` —
|
|
113
113
|
* it does NOT auto-migrate from a previous tracking table. A project that
|
|
114
|
-
* has been running with `
|
|
114
|
+
* has been running with `ream_migrations` and then changes `tableName` to
|
|
115
115
|
* `schema_versions` will get a fresh empty `schema_versions` on next boot,
|
|
116
116
|
* read zero applied migrations, and re-run every past migration (likely
|
|
117
117
|
* crashing on `CREATE TABLE <user-table>` already-exists). To rename
|
|
118
118
|
* safely, copy the history manually before switching:
|
|
119
119
|
*
|
|
120
|
-
* INSERT INTO schema_versions SELECT * FROM
|
|
121
|
-
* -- (then DROP TABLE
|
|
120
|
+
* INSERT INTO schema_versions SELECT * FROM ream_migrations;
|
|
121
|
+
* -- (then DROP TABLE ream_migrations once verified)
|
|
122
122
|
*/
|
|
123
123
|
constructor(
|
|
124
124
|
db: DatabaseAdapter,
|
|
@@ -137,16 +137,20 @@ export class MigrationRunner {
|
|
|
137
137
|
: validateTrackingTableName(options.tableName);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
/** Ensure the
|
|
140
|
+
/** Ensure the ream_migrations tracking table exists. */
|
|
141
141
|
async init(): Promise<void> {
|
|
142
142
|
await runStmt(this.#db, this.#dialect, {
|
|
143
143
|
kind: "createTable",
|
|
144
144
|
table: this.#tableName,
|
|
145
145
|
ifNotExists: true,
|
|
146
146
|
columns: [
|
|
147
|
+
// Auto-increment PK (Lucid's adonis_schema uses `increments`). The
|
|
148
|
+
// Rust compiler emits the dialect-appropriate identity clause, so
|
|
149
|
+
// the INSERT below omits `id` on every dialect.
|
|
147
150
|
{
|
|
148
151
|
name: "id",
|
|
149
152
|
kind: "integer",
|
|
153
|
+
autoIncrement: true,
|
|
150
154
|
nullable: false,
|
|
151
155
|
primary: true,
|
|
152
156
|
unique: false,
|
|
@@ -257,7 +261,7 @@ export class MigrationRunner {
|
|
|
257
261
|
const migration = await this.#loadMigration(name);
|
|
258
262
|
const statements = await migration.getUpSQL();
|
|
259
263
|
|
|
260
|
-
// Compile the
|
|
264
|
+
// Compile the ream_migrations INSERT so we can include it in the same
|
|
261
265
|
// transaction as the migration's own DDL/DML — either everything
|
|
262
266
|
// commits or nothing does.
|
|
263
267
|
const insertCompiled = compileStatementNative(
|
|
@@ -36,6 +36,21 @@ export class TableBuilder {
|
|
|
36
36
|
return this.#addColumn(name, "uuid");
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Auto-incrementing integer primary key (Lucid `increments()`). The Rust
|
|
41
|
+
* compiler emits the dialect-appropriate identity clause (SQLite
|
|
42
|
+
* `AUTOINCREMENT`, Postgres `GENERATED ... AS IDENTITY`, MySQL
|
|
43
|
+
* `AUTO_INCREMENT`). For a 64-bit key use `bigIncrements()`.
|
|
44
|
+
*/
|
|
45
|
+
increments(name = "id"): this {
|
|
46
|
+
return this.#addIncrements(name, "integer");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Auto-incrementing 64-bit primary key (Lucid `bigIncrements()`). */
|
|
50
|
+
bigIncrements(name = "id"): this {
|
|
51
|
+
return this.#addIncrements(name, "bigInteger");
|
|
52
|
+
}
|
|
53
|
+
|
|
39
54
|
string(name: string, length = 255): this {
|
|
40
55
|
this.#addColumn(name, "string");
|
|
41
56
|
if (this.#currentColumn) this.#currentColumn.length = length;
|
|
@@ -209,6 +224,7 @@ export class TableBuilder {
|
|
|
209
224
|
scale: c.scale ?? null,
|
|
210
225
|
nullable: c.nullable,
|
|
211
226
|
primary: c.primary,
|
|
227
|
+
autoIncrement: c.autoIncrement ?? false,
|
|
212
228
|
unique: c.unique,
|
|
213
229
|
default: c.defaultValue ?? null,
|
|
214
230
|
references: c.references ?? null,
|
|
@@ -235,4 +251,14 @@ export class TableBuilder {
|
|
|
235
251
|
this.#currentColumn = col;
|
|
236
252
|
return this;
|
|
237
253
|
}
|
|
254
|
+
|
|
255
|
+
#addIncrements(name: string, type: "integer" | "bigInteger"): this {
|
|
256
|
+
this.#addColumn(name, type);
|
|
257
|
+
if (this.#currentColumn) {
|
|
258
|
+
this.#currentColumn.autoIncrement = true;
|
|
259
|
+
this.#currentColumn.primary = true;
|
|
260
|
+
this.#currentColumn.nullable = false;
|
|
261
|
+
}
|
|
262
|
+
return this;
|
|
263
|
+
}
|
|
238
264
|
}
|
package/src/schema/types.ts
CHANGED
|
@@ -39,6 +39,8 @@ export interface ColumnDefinition {
|
|
|
39
39
|
scale?: number;
|
|
40
40
|
nullable: boolean;
|
|
41
41
|
primary: boolean;
|
|
42
|
+
/** Dialect-appropriate auto-increment / identity column (Lucid `increments`). Implies primary key. */
|
|
43
|
+
autoIncrement?: boolean;
|
|
42
44
|
unique: boolean;
|
|
43
45
|
defaultValue?: string;
|
|
44
46
|
references?: { table: string; column: string };
|
|
@@ -21,20 +21,19 @@ export async function useTransaction(
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Truncate all user tables (excludes
|
|
24
|
+
* Truncate all user tables (excludes ream_* framework tables and SQLite internals).
|
|
25
25
|
*
|
|
26
26
|
* The SELECT on `sqlite_master` is SQLite-specific introspection and is kept
|
|
27
27
|
* as raw SQL intentionally — it's not a user query. The resulting DELETEs
|
|
28
28
|
* go through the Rust compiler.
|
|
29
29
|
*/
|
|
30
30
|
export async function truncateAll(db: AsyncDatabaseConnection): Promise<void> {
|
|
31
|
-
// SQL LIKE `_` is a single-char wildcard, not a literal underscore
|
|
32
|
-
// `
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
// for framework-private tables, including `_migrations`).
|
|
31
|
+
// SQL LIKE `_` is a single-char wildcard, not a literal underscore, so the
|
|
32
|
+
// `ESCAPE '\'` clause makes `\_` a literal underscore. The exclusion targets
|
|
33
|
+
// names starting with `ream_` (the convention for framework-private tables,
|
|
34
|
+
// including `ream_migrations`) and SQLite's own `sqlite_%` tables.
|
|
36
35
|
const tables = await db.query(
|
|
37
|
-
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE '\\_%' ESCAPE '\\' AND name NOT LIKE 'sqlite_%'",
|
|
36
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'ream\\_%' ESCAPE '\\' AND name NOT LIKE 'sqlite_%'",
|
|
38
37
|
);
|
|
39
38
|
const dialect = getAtlasDialect();
|
|
40
39
|
for (const row of tables) {
|