@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.
Files changed (150) hide show
  1. package/db.darwin-arm64.node +0 -0
  2. package/db.darwin-x64.node +0 -0
  3. package/db.linux-arm64-gnu.node +0 -0
  4. package/db.linux-x64-gnu.node +0 -0
  5. package/db.win32-x64-msvc.node +0 -0
  6. package/dist/AtlasProvider.d.ts +106 -0
  7. package/dist/AtlasProvider.d.ts.map +1 -0
  8. package/dist/AtlasProvider.js +190 -0
  9. package/dist/AtlasProvider.js.map +1 -0
  10. package/dist/BaseEntity.d.ts +255 -0
  11. package/dist/BaseEntity.d.ts.map +1 -0
  12. package/dist/BaseEntity.js +420 -0
  13. package/dist/BaseEntity.js.map +1 -0
  14. package/dist/BaseRepository.d.ts +175 -0
  15. package/dist/BaseRepository.d.ts.map +1 -0
  16. package/dist/BaseRepository.js +1451 -0
  17. package/dist/BaseRepository.js.map +1 -0
  18. package/dist/ModelQuery.d.ts +338 -0
  19. package/dist/ModelQuery.d.ts.map +1 -0
  20. package/dist/ModelQuery.js +1598 -0
  21. package/dist/ModelQuery.js.map +1 -0
  22. package/dist/Transaction.d.ts +15 -0
  23. package/dist/Transaction.d.ts.map +1 -0
  24. package/dist/Transaction.js +67 -0
  25. package/dist/Transaction.js.map +1 -0
  26. package/dist/adapters/NapiDbAdapter.d.ts +34 -0
  27. package/dist/adapters/NapiDbAdapter.d.ts.map +1 -0
  28. package/dist/adapters/NapiDbAdapter.js +96 -0
  29. package/dist/adapters/NapiDbAdapter.js.map +1 -0
  30. package/dist/config.d.ts +4 -0
  31. package/dist/config.d.ts.map +1 -0
  32. package/dist/config.js +4 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/configure.d.ts +10 -0
  35. package/dist/configure.d.ts.map +1 -0
  36. package/dist/configure.js +25 -0
  37. package/dist/configure.js.map +1 -0
  38. package/dist/decorators/entity.d.ts +235 -0
  39. package/dist/decorators/entity.d.ts.map +1 -0
  40. package/dist/decorators/entity.js +264 -0
  41. package/dist/decorators/entity.js.map +1 -0
  42. package/dist/decorators/hooks.d.ts +70 -0
  43. package/dist/decorators/hooks.d.ts.map +1 -0
  44. package/dist/decorators/hooks.js +107 -0
  45. package/dist/decorators/hooks.js.map +1 -0
  46. package/dist/decorators/scope.d.ts +35 -0
  47. package/dist/decorators/scope.d.ts.map +1 -0
  48. package/dist/decorators/scope.js +29 -0
  49. package/dist/decorators/scope.js.map +1 -0
  50. package/dist/errors.d.ts +54 -0
  51. package/dist/errors.d.ts.map +1 -0
  52. package/dist/errors.js +82 -0
  53. package/dist/errors.js.map +1 -0
  54. package/dist/index.d.ts +39 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +28 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/naming/NamingStrategy.d.ts +52 -0
  59. package/dist/naming/NamingStrategy.d.ts.map +1 -0
  60. package/dist/naming/NamingStrategy.js +65 -0
  61. package/dist/naming/NamingStrategy.js.map +1 -0
  62. package/dist/query/QueryBuilder.d.ts +95 -0
  63. package/dist/query/QueryBuilder.d.ts.map +1 -0
  64. package/dist/query/QueryBuilder.js +310 -0
  65. package/dist/query/QueryBuilder.js.map +1 -0
  66. package/dist/query/native.d.ts +18 -0
  67. package/dist/query/native.d.ts.map +1 -0
  68. package/dist/query/native.js +49 -0
  69. package/dist/query/native.js.map +1 -0
  70. package/dist/schema/Migration.d.ts +55 -0
  71. package/dist/schema/Migration.d.ts.map +1 -0
  72. package/dist/schema/Migration.js +68 -0
  73. package/dist/schema/Migration.js.map +1 -0
  74. package/dist/schema/MigrationRunner.d.ts +115 -0
  75. package/dist/schema/MigrationRunner.d.ts.map +1 -0
  76. package/dist/schema/MigrationRunner.js +406 -0
  77. package/dist/schema/MigrationRunner.js.map +1 -0
  78. package/dist/schema/Schema.d.ts +22 -0
  79. package/dist/schema/Schema.d.ts.map +1 -0
  80. package/dist/schema/Schema.js +51 -0
  81. package/dist/schema/Schema.js.map +1 -0
  82. package/dist/schema/SchemaBuilder.d.ts +14 -0
  83. package/dist/schema/SchemaBuilder.d.ts.map +1 -0
  84. package/dist/schema/SchemaBuilder.js +13 -0
  85. package/dist/schema/SchemaBuilder.js.map +1 -0
  86. package/dist/schema/Seeder.d.ts +54 -0
  87. package/dist/schema/Seeder.d.ts.map +1 -0
  88. package/dist/schema/Seeder.js +89 -0
  89. package/dist/schema/Seeder.js.map +1 -0
  90. package/dist/schema/TableBuilder.d.ts +95 -0
  91. package/dist/schema/TableBuilder.d.ts.map +1 -0
  92. package/dist/schema/TableBuilder.js +234 -0
  93. package/dist/schema/TableBuilder.js.map +1 -0
  94. package/dist/schema/types.d.ts +30 -0
  95. package/dist/schema/types.d.ts.map +1 -0
  96. package/dist/schema/types.js +19 -0
  97. package/dist/schema/types.js.map +1 -0
  98. package/dist/services/db.d.ts +22 -0
  99. package/dist/services/db.d.ts.map +1 -0
  100. package/dist/services/db.js +37 -0
  101. package/dist/services/db.js.map +1 -0
  102. package/dist/testing/DatabaseCleanup.d.ts +19 -0
  103. package/dist/testing/DatabaseCleanup.d.ts.map +1 -0
  104. package/dist/testing/DatabaseCleanup.js +39 -0
  105. package/dist/testing/DatabaseCleanup.js.map +1 -0
  106. package/dist/testing/Factory.d.ts +59 -0
  107. package/dist/testing/Factory.d.ts.map +1 -0
  108. package/dist/testing/Factory.js +105 -0
  109. package/dist/testing/Factory.js.map +1 -0
  110. package/dist/testing/TestDatabase.d.ts +25 -0
  111. package/dist/testing/TestDatabase.d.ts.map +1 -0
  112. package/dist/testing/TestDatabase.js +52 -0
  113. package/dist/testing/TestDatabase.js.map +1 -0
  114. package/dist/testing/index.d.ts +4 -0
  115. package/dist/testing/index.d.ts.map +1 -0
  116. package/dist/testing/index.js +4 -0
  117. package/dist/testing/index.js.map +1 -0
  118. package/dist/utils/casing.d.ts +5 -0
  119. package/dist/utils/casing.d.ts.map +1 -0
  120. package/dist/utils/casing.js +9 -0
  121. package/dist/utils/casing.js.map +1 -0
  122. package/dist/utils/dialectFromUrl.d.ts +10 -0
  123. package/dist/utils/dialectFromUrl.d.ts.map +1 -0
  124. package/dist/utils/dialectFromUrl.js +8 -0
  125. package/dist/utils/dialectFromUrl.js.map +1 -0
  126. package/dist/utils/identifier.d.ts +19 -0
  127. package/dist/utils/identifier.d.ts.map +1 -0
  128. package/dist/utils/identifier.js +27 -0
  129. package/dist/utils/identifier.js.map +1 -0
  130. package/dist/utils/safePath.d.ts +22 -0
  131. package/dist/utils/safePath.d.ts.map +1 -0
  132. package/dist/utils/safePath.js +46 -0
  133. package/dist/utils/safePath.js.map +1 -0
  134. package/dist/utils/transactionBrand.d.ts +5 -0
  135. package/dist/utils/transactionBrand.d.ts.map +1 -0
  136. package/dist/utils/transactionBrand.js +5 -0
  137. package/dist/utils/transactionBrand.js.map +1 -0
  138. package/index.darwin-arm64.node +0 -0
  139. package/index.darwin-x64.node +0 -0
  140. package/index.linux-arm64-gnu.node +0 -0
  141. package/index.linux-x64-gnu.node +0 -0
  142. package/index.win32-x64-msvc.node +0 -0
  143. package/package.json +1 -1
  144. package/src/AtlasProvider.ts +2 -2
  145. package/src/BaseRepository.ts +73 -11
  146. package/src/adapters/NapiDbAdapter.ts +1 -1
  147. package/src/schema/MigrationRunner.ts +16 -12
  148. package/src/schema/TableBuilder.ts +26 -0
  149. package/src/schema/types.ts +2 -0
  150. package/src/testing/DatabaseCleanup.ts +6 -7
@@ -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
- { kind: "update", table: this.#tableName, set, wheres },
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
- : { kind: "insert", table: this.#tableName, values };
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
- const spec = { kind: "insert", table: pivotTable, rows: rowPairs };
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 `_migrations` bookkeeping.
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 = "_migrations";
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 `"_migrations"`. Must match `/^[A-Za-z_][A-Za-z0-9_]*$/` —
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 a literal `_` (via `LIKE '\_%' ESCAPE '\'`).
107
- * The default `"_migrations"` is therefore auto-protected. Choosing a non-`_`
108
- * prefix (e.g. `"schema_versions"`) opts the tracking table out of that
109
- * protection — `truncateAll` will wipe it alongside user tables, forcing a
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 `_migrations` and then changes `tableName` to
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 _migrations;
121
- * -- (then DROP TABLE _migrations once verified)
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 _migrations tracking table exists. */
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 _migrations INSERT so we can include it in the same
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
  }
@@ -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 _migrations and internal tables).
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
- // `NOT LIKE '_%'` without `ESCAPE` matches NOTHING (every non-empty name
33
- // matches `_%`). The `ESCAPE '\'` clause makes `\_` a literal underscore,
34
- // so the exclusion targets only names starting with `_` (the convention
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) {