@c9up/atlas 0.2.0 → 0.2.1

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 (234) hide show
  1. package/README.md +8 -0
  2. package/db.darwin-arm64.node +0 -0
  3. package/db.darwin-x64.node +0 -0
  4. package/db.linux-arm64-gnu.node +0 -0
  5. package/db.linux-x64-gnu.node +0 -0
  6. package/db.win32-x64-msvc.node +0 -0
  7. package/dist/AtlasProvider.d.ts +60 -7
  8. package/dist/AtlasProvider.d.ts.map +1 -1
  9. package/dist/AtlasProvider.js +204 -38
  10. package/dist/AtlasProvider.js.map +1 -1
  11. package/dist/BaseEntity.d.ts +17 -0
  12. package/dist/BaseEntity.d.ts.map +1 -1
  13. package/dist/BaseEntity.js.map +1 -1
  14. package/dist/BaseModel.d.ts +63 -27
  15. package/dist/BaseModel.d.ts.map +1 -1
  16. package/dist/BaseModel.js +108 -51
  17. package/dist/BaseModel.js.map +1 -1
  18. package/dist/BaseRepository.d.ts +11 -1
  19. package/dist/BaseRepository.d.ts.map +1 -1
  20. package/dist/BaseRepository.js +95 -20
  21. package/dist/BaseRepository.js.map +1 -1
  22. package/dist/ConnectionManager.d.ts +106 -0
  23. package/dist/ConnectionManager.d.ts.map +1 -0
  24. package/dist/ConnectionManager.js +228 -0
  25. package/dist/ConnectionManager.js.map +1 -0
  26. package/dist/ModelQuery.d.ts +256 -43
  27. package/dist/ModelQuery.d.ts.map +1 -1
  28. package/dist/ModelQuery.js +899 -231
  29. package/dist/ModelQuery.js.map +1 -1
  30. package/dist/Transaction.d.ts +54 -1
  31. package/dist/Transaction.d.ts.map +1 -1
  32. package/dist/Transaction.js +121 -59
  33. package/dist/Transaction.js.map +1 -1
  34. package/dist/adapters/NapiDbAdapter.d.ts +11 -0
  35. package/dist/adapters/NapiDbAdapter.d.ts.map +1 -1
  36. package/dist/adapters/NapiDbAdapter.js +35 -7
  37. package/dist/adapters/NapiDbAdapter.js.map +1 -1
  38. package/dist/console/contract.d.ts +62 -0
  39. package/dist/console/contract.d.ts.map +1 -0
  40. package/dist/console/contract.js +38 -0
  41. package/dist/console/contract.js.map +1 -0
  42. package/dist/console/factoryCommands.d.ts +23 -0
  43. package/dist/console/factoryCommands.d.ts.map +1 -0
  44. package/dist/console/factoryCommands.js +62 -0
  45. package/dist/console/factoryCommands.js.map +1 -0
  46. package/dist/console/migrationCommands.d.ts +38 -8
  47. package/dist/console/migrationCommands.d.ts.map +1 -1
  48. package/dist/console/migrationCommands.js +157 -50
  49. package/dist/console/migrationCommands.js.map +1 -1
  50. package/dist/console/schemaCheckCommand.d.ts +11 -17
  51. package/dist/console/schemaCheckCommand.d.ts.map +1 -1
  52. package/dist/console/schemaCheckCommand.js +21 -15
  53. package/dist/console/schemaCheckCommand.js.map +1 -1
  54. package/dist/console/schemaDumpCommand.d.ts +30 -0
  55. package/dist/console/schemaDumpCommand.d.ts.map +1 -0
  56. package/dist/console/schemaDumpCommand.js +69 -0
  57. package/dist/console/schemaDumpCommand.js.map +1 -0
  58. package/dist/console/schemaGenerateCommand.d.ts +100 -0
  59. package/dist/console/schemaGenerateCommand.d.ts.map +1 -0
  60. package/dist/console/schemaGenerateCommand.js +246 -0
  61. package/dist/console/schemaGenerateCommand.js.map +1 -0
  62. package/dist/console/seederCommands.d.ts +46 -0
  63. package/dist/console/seederCommands.d.ts.map +1 -0
  64. package/dist/console/seederCommands.js +136 -0
  65. package/dist/console/seederCommands.js.map +1 -0
  66. package/dist/decorators/entity.d.ts +13 -2
  67. package/dist/decorators/entity.d.ts.map +1 -1
  68. package/dist/decorators/entity.js +10 -0
  69. package/dist/decorators/entity.js.map +1 -1
  70. package/dist/decorators/hooks.d.ts +3 -3
  71. package/dist/decorators/hooks.d.ts.map +1 -1
  72. package/dist/decorators/hooks.js.map +1 -1
  73. package/dist/events.d.ts +5 -0
  74. package/dist/events.d.ts.map +1 -1
  75. package/dist/events.js.map +1 -1
  76. package/dist/factories.d.ts +8 -0
  77. package/dist/factories.d.ts.map +1 -0
  78. package/dist/factories.js +8 -0
  79. package/dist/factories.js.map +1 -0
  80. package/dist/index.d.ts +11 -5
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +12 -4
  83. package/dist/index.js.map +1 -1
  84. package/dist/lucid-schema.d.ts +15 -0
  85. package/dist/lucid-schema.d.ts.map +1 -0
  86. package/dist/lucid-schema.js +16 -0
  87. package/dist/lucid-schema.js.map +1 -0
  88. package/dist/orm.d.ts +14 -0
  89. package/dist/orm.d.ts.map +1 -0
  90. package/dist/orm.js +14 -0
  91. package/dist/orm.js.map +1 -0
  92. package/dist/query/DatabaseQueryBuilder.d.ts +557 -0
  93. package/dist/query/DatabaseQueryBuilder.d.ts.map +1 -0
  94. package/dist/query/DatabaseQueryBuilder.js +1798 -0
  95. package/dist/query/DatabaseQueryBuilder.js.map +1 -0
  96. package/dist/query/DmlBuilder.d.ts +62 -0
  97. package/dist/query/DmlBuilder.d.ts.map +1 -0
  98. package/dist/query/DmlBuilder.js +84 -0
  99. package/dist/query/DmlBuilder.js.map +1 -0
  100. package/dist/query/QueryBuilder.d.ts +5 -0
  101. package/dist/query/QueryBuilder.d.ts.map +1 -1
  102. package/dist/query/QueryBuilder.js +7 -0
  103. package/dist/query/QueryBuilder.js.map +1 -1
  104. package/dist/query/RawQueryBuilder.d.ts +47 -0
  105. package/dist/query/RawQueryBuilder.d.ts.map +1 -0
  106. package/dist/query/RawQueryBuilder.js +138 -0
  107. package/dist/query/RawQueryBuilder.js.map +1 -0
  108. package/dist/query/interpolate.d.ts +45 -0
  109. package/dist/query/interpolate.d.ts.map +1 -0
  110. package/dist/query/interpolate.js +51 -0
  111. package/dist/query/interpolate.js.map +1 -0
  112. package/dist/query/native.d.ts +8 -0
  113. package/dist/query/native.d.ts.map +1 -1
  114. package/dist/query/native.js +14 -0
  115. package/dist/query/native.js.map +1 -1
  116. package/dist/query/operators.d.ts +4 -0
  117. package/dist/query/operators.d.ts.map +1 -0
  118. package/dist/query/operators.js +27 -0
  119. package/dist/query/operators.js.map +1 -0
  120. package/dist/schema/Migration.d.ts +31 -7
  121. package/dist/schema/Migration.d.ts.map +1 -1
  122. package/dist/schema/Migration.js +34 -7
  123. package/dist/schema/Migration.js.map +1 -1
  124. package/dist/schema/MigrationRunner.d.ts +56 -6
  125. package/dist/schema/MigrationRunner.d.ts.map +1 -1
  126. package/dist/schema/MigrationRunner.js +382 -112
  127. package/dist/schema/MigrationRunner.js.map +1 -1
  128. package/dist/schema/Schema.d.ts +59 -2
  129. package/dist/schema/Schema.d.ts.map +1 -1
  130. package/dist/schema/Schema.js +143 -9
  131. package/dist/schema/Schema.js.map +1 -1
  132. package/dist/schema/SchemaDumper.d.ts +121 -0
  133. package/dist/schema/SchemaDumper.d.ts.map +1 -0
  134. package/dist/schema/SchemaDumper.js +365 -0
  135. package/dist/schema/SchemaDumper.js.map +1 -0
  136. package/dist/schema/Seeder.d.ts +13 -0
  137. package/dist/schema/Seeder.d.ts.map +1 -1
  138. package/dist/schema/Seeder.js +28 -5
  139. package/dist/schema/Seeder.js.map +1 -1
  140. package/dist/schema/TableBuilder.d.ts +27 -8
  141. package/dist/schema/TableBuilder.d.ts.map +1 -1
  142. package/dist/schema/TableBuilder.js +50 -12
  143. package/dist/schema/TableBuilder.js.map +1 -1
  144. package/dist/schema/catalog.d.ts +25 -1
  145. package/dist/schema/catalog.d.ts.map +1 -1
  146. package/dist/schema/catalog.js +69 -22
  147. package/dist/schema/catalog.js.map +1 -1
  148. package/dist/schema/introspect.d.ts +1 -1
  149. package/dist/schema/introspect.d.ts.map +1 -1
  150. package/dist/schema/introspect.js +26 -11
  151. package/dist/schema/introspect.js.map +1 -1
  152. package/dist/seeders.d.ts +7 -0
  153. package/dist/seeders.d.ts.map +1 -0
  154. package/dist/seeders.js +7 -0
  155. package/dist/seeders.js.map +1 -0
  156. package/dist/services/db.d.ts +120 -9
  157. package/dist/services/db.d.ts.map +1 -1
  158. package/dist/services/db.js +182 -26
  159. package/dist/services/db.js.map +1 -1
  160. package/dist/testing/DatabaseCleanup.d.ts +29 -6
  161. package/dist/testing/DatabaseCleanup.d.ts.map +1 -1
  162. package/dist/testing/DatabaseCleanup.js +44 -17
  163. package/dist/testing/DatabaseCleanup.js.map +1 -1
  164. package/dist/testing/DbAssertions.d.ts +48 -0
  165. package/dist/testing/DbAssertions.d.ts.map +1 -0
  166. package/dist/testing/DbAssertions.js +80 -0
  167. package/dist/testing/DbAssertions.js.map +1 -0
  168. package/dist/testing/Factory.d.ts +111 -25
  169. package/dist/testing/Factory.d.ts.map +1 -1
  170. package/dist/testing/Factory.js +331 -56
  171. package/dist/testing/Factory.js.map +1 -1
  172. package/dist/testing/TestUtils.d.ts +49 -0
  173. package/dist/testing/TestUtils.d.ts.map +1 -0
  174. package/dist/testing/TestUtils.js +79 -0
  175. package/dist/testing/TestUtils.js.map +1 -0
  176. package/dist/testing/index.d.ts +3 -1
  177. package/dist/testing/index.d.ts.map +1 -1
  178. package/dist/testing/index.js +3 -1
  179. package/dist/testing/index.js.map +1 -1
  180. package/dist/types/relations.d.ts +31 -0
  181. package/dist/types/relations.d.ts.map +1 -0
  182. package/dist/types/relations.js +20 -0
  183. package/dist/types/relations.js.map +1 -0
  184. package/index.darwin-arm64.node +0 -0
  185. package/index.darwin-x64.node +0 -0
  186. package/index.linux-arm64-gnu.node +0 -0
  187. package/index.linux-x64-gnu.node +0 -0
  188. package/index.win32-x64-msvc.node +0 -0
  189. package/package.json +30 -2
  190. package/src/AtlasProvider.ts +297 -51
  191. package/src/BaseEntity.ts +29 -0
  192. package/src/BaseModel.ts +174 -37
  193. package/src/BaseRepository.ts +136 -17
  194. package/src/ConnectionManager.ts +298 -0
  195. package/src/ModelQuery.ts +1309 -260
  196. package/src/Transaction.ts +194 -60
  197. package/src/adapters/NapiDbAdapter.ts +72 -14
  198. package/src/console/contract.ts +96 -0
  199. package/src/console/factoryCommands.ts +73 -0
  200. package/src/console/migrationCommands.ts +253 -63
  201. package/src/console/schemaCheckCommand.ts +26 -22
  202. package/src/console/schemaDumpCommand.ts +96 -0
  203. package/src/console/schemaGenerateCommand.ts +380 -0
  204. package/src/console/seederCommands.ts +174 -0
  205. package/src/decorators/entity.ts +18 -2
  206. package/src/decorators/hooks.ts +5 -3
  207. package/src/events.ts +5 -0
  208. package/src/factories.ts +10 -0
  209. package/src/index.ts +50 -3
  210. package/src/lucid-schema.ts +22 -0
  211. package/src/orm.ts +13 -0
  212. package/src/query/DatabaseQueryBuilder.ts +2724 -0
  213. package/src/query/DmlBuilder.ts +131 -0
  214. package/src/query/QueryBuilder.ts +8 -0
  215. package/src/query/RawQueryBuilder.ts +173 -0
  216. package/src/query/interpolate.ts +73 -0
  217. package/src/query/native.ts +29 -0
  218. package/src/query/operators.ts +27 -0
  219. package/src/schema/Migration.ts +36 -7
  220. package/src/schema/MigrationRunner.ts +483 -119
  221. package/src/schema/Schema.ts +168 -19
  222. package/src/schema/SchemaDumper.ts +518 -0
  223. package/src/schema/Seeder.ts +47 -10
  224. package/src/schema/TableBuilder.ts +48 -11
  225. package/src/schema/catalog.ts +94 -24
  226. package/src/schema/introspect.ts +26 -9
  227. package/src/seeders.ts +16 -0
  228. package/src/services/db.ts +343 -31
  229. package/src/testing/DatabaseCleanup.ts +73 -21
  230. package/src/testing/DbAssertions.ts +127 -0
  231. package/src/testing/Factory.ts +559 -79
  232. package/src/testing/TestUtils.ts +123 -0
  233. package/src/testing/index.ts +12 -1
  234. package/src/types/relations.ts +43 -0
@@ -12,17 +12,121 @@
12
12
  * swap in a custom `AsyncDatabaseConnection` through the provider's
13
13
  * container hooks).
14
14
  */
15
+ import type { ConnectionConfig } from "../AtlasProvider.js";
15
16
  import type { AsyncDatabaseConnection } from "../adapters/NapiDbAdapter.js";
17
+ import { ConnectionManager } from "../ConnectionManager.js";
18
+ import { DatabaseQueryBuilder, type QueryExecutor } from "../query/DatabaseQueryBuilder.js";
19
+ import type { AtlasDialect } from "../query/native.js";
16
20
  import { RawSql } from "../query/QueryBuilder.js";
17
- /** The `db` singleton surface: the bound connection plus the AdonisJS-style `db.raw()` builder. */
18
- export interface DbService extends AsyncDatabaseConnection {
21
+ import { RawQueryBuilder } from "../query/RawQueryBuilder.js";
22
+ /** Options accepted by the Lucid query-builder entry points. */
23
+ export interface DbQueryOptions {
24
+ /** Route the query through this transaction client (Lucid `{ client: trx }`). */
25
+ client?: QueryExecutor;
26
+ /** `'read'` rejects writes on this builder (Lucid `db.query({ mode: 'read' })`). */
27
+ mode?: "read" | "write";
28
+ }
29
+ /** Options for {@link DbService.connection} (Lucid read/write replica routing). */
30
+ export interface ConnectionOptions {
19
31
  /**
20
- * Build a raw SQL expression AdonisJS `db.raw()` / `Database.raw()`. Use it
21
- * for query fragments and for column defaults that are SQL expressions:
32
+ * `'read'` scopes the returned service to reads: its query builders reject
33
+ * writes (insert/update/delete/increment/decrement). `'write'` (default) is
34
+ * unrestricted. Atlas has no replica pool, so `mode` is a write-guard rather
35
+ * than a routing hint — the guard is the security-relevant half of Lucid's
36
+ * read/write modes.
37
+ */
38
+ mode?: "read" | "write";
39
+ }
40
+ /**
41
+ * The `db` service surface — Adonis Lucid's `Database` service. Exposes the
42
+ * query builders (`query`/`from`/`table`/`insertQuery`), raw execution
43
+ * (`rawQuery`), the `raw()` fragment builder, connection scoping (`connection`),
44
+ * and the transaction/DDL methods forwarded from the bound connection.
45
+ */
46
+ export interface DbService {
47
+ /** A connection-level query builder (Lucid `db.query()`), optionally on a trx. */
48
+ query(options?: DbQueryOptions): DatabaseQueryBuilder;
49
+ /** Query builder with the table pre-selected (Lucid `db.from(table)`). */
50
+ from(table: string): DatabaseQueryBuilder;
51
+ /**
52
+ * Query builder on a derived-table source (Lucid `db.from(subquery, alias)`) —
53
+ * a builder OR a callback that builds one.
54
+ */
55
+ from(subquery: DatabaseQueryBuilder | ((query: DatabaseQueryBuilder) => void), alias?: string): DatabaseQueryBuilder;
56
+ /** Insert/write builder with the table pre-selected (Lucid `db.table(table)`). */
57
+ table(table: string): DatabaseQueryBuilder;
58
+ /** An insert builder (Lucid `db.insertQuery()`), optionally on a trx. */
59
+ insertQuery(options?: DbQueryOptions): DatabaseQueryBuilder;
60
+ /**
61
+ * A chainable raw query (Lucid `db.rawQuery(sql, bindings)`). Thenable — can be
62
+ * awaited directly — and exposes `toSQL`/`toQuery`/`debug`/`timeout`/
63
+ * `reporterData`. Bindings may be positional (`?`/`??`) or named (`:name`/`:name:`).
64
+ */
65
+ rawQuery<T = Record<string, unknown>>(sql: string, bindings?: unknown[] | Record<string, unknown>): RawQueryBuilder<T>;
66
+ /**
67
+ * Scope the service to a connection (Lucid `db.connection(name)`). Called with
68
+ * no name it returns the default connection's service (Lucid `db.connection()`).
69
+ * Pass `{ mode: 'read' }` to reject writes on the returned service (Lucid
70
+ * `db.connection(name, { mode: 'read' })`).
71
+ */
72
+ connection(name?: string, options?: ConnectionOptions): DbService;
73
+ /**
74
+ * Query builder for a model whose class is resolved at runtime (Lucid
75
+ * `db.modelQuery(Model)`). For static code prefer `Model.query()` directly.
76
+ */
77
+ modelQuery<Q>(model: {
78
+ query(): Q;
79
+ }): Q;
80
+ /**
81
+ * Build a raw SQL expression — AdonisJS `db.raw()`. For query fragments and
82
+ * column defaults that are SQL expressions:
22
83
  *
23
84
  * t.uuid('id').defaultTo(db.raw('gen_random_uuid()'))
85
+ *
86
+ * Bindings may be positional (`?`/`??`) or named (`:name`/`:name:`).
87
+ */
88
+ raw(sql: string, params?: unknown[] | Record<string, unknown>): RawSql;
89
+ /**
90
+ * A column reference — Adonis Lucid `db.ref('posts.created_at')`. Use it where
91
+ * a value position must be read as a column (e.g. `orderBy(db.ref(col), 'desc')`).
92
+ * The identifier is validated and dialect-quoted; it is NOT a value binding.
93
+ */
94
+ ref(column: string): RawSql;
95
+ /** Run a statement for effect (forwarded to the connection). */
96
+ execute(sql: string, params?: unknown[]): Promise<{
97
+ rowsAffected: number;
98
+ }>;
99
+ /** Managed/manual interactive transaction (forwarded, Lucid `db.transaction`). */
100
+ transaction: AsyncDatabaseConnection["transaction"];
101
+ /** Atomic batch (forwarded). */
102
+ runInTransaction: AsyncDatabaseConnection["runInTransaction"];
103
+ /**
104
+ * Empty a table (Lucid `truncate`). `TRUNCATE TABLE` on Postgres/MySQL (with
105
+ * `CASCADE` when `cascade` is set, Postgres only); `DELETE FROM` on SQLite,
106
+ * which has no `TRUNCATE`.
24
107
  */
25
- raw(sql: string, params?: unknown[]): RawSql;
108
+ truncate(table: string, cascade?: boolean): Promise<void>;
109
+ /**
110
+ * Empty every user table (Lucid `truncateAllTables`). Framework tables
111
+ * (`ream_*`) and dialect internals are left alone; pass `ignoreTables` to spare
112
+ * more. Foreign keys are suspended so delete order doesn't matter.
113
+ */
114
+ truncateAllTables(ignoreTables?: readonly string[]): Promise<void>;
115
+ /**
116
+ * Try to acquire a session-level advisory lock, non-blocking (Lucid
117
+ * `getAdvisoryLock`). Postgres `pg_try_advisory_lock`, MySQL `GET_LOCK(key, 0)`.
118
+ * A string key is hashed to the integer Postgres requires. Returns whether the
119
+ * lock was acquired. **Throws on SQLite** (no advisory locks — Lucid parity).
120
+ */
121
+ getAdvisoryLock(key: string | number): Promise<boolean>;
122
+ /** Release an advisory lock taken with {@link getAdvisoryLock}. Throws on SQLite. */
123
+ releaseAdvisoryLock(key: string | number): Promise<boolean>;
124
+ /** The full Lucid connection manager (`add`/`connect`/`patch`/`release`/nodes/events). */
125
+ readonly manager: ConnectionManager;
126
+ /** The bound connection's dialect. */
127
+ readonly dialect: AtlasDialect;
128
+ ping(): Promise<void>;
129
+ close(): Promise<void>;
26
130
  }
27
131
  /** @internal Bind the singleton (called by AtlasProvider). */
28
132
  export declare function setDb(connection: AsyncDatabaseConnection): void;
@@ -35,12 +139,19 @@ export declare function setDb(connection: AsyncDatabaseConnection): void;
35
139
  export declare function clearDb(connection: AsyncDatabaseConnection): void;
36
140
  /** @internal Read the singleton (or `undefined` pre-boot). */
37
141
  export declare function getDb(): AsyncDatabaseConnection | undefined;
38
- /** @internal Register a named connection (called by AtlasProvider.boot per connection). */
39
- export declare function registerConnection(name: string, connection: AsyncDatabaseConnection): void;
40
- /** @internal Unregister a named connection IF it still points at `connection`. */
142
+ /**
143
+ * @internal Register an already-open named connection (called by AtlasProvider,
144
+ * which opens connections itself). Records the config on the node too.
145
+ */
146
+ export declare function registerConnection(name: string, connection: AsyncDatabaseConnection, config?: ConnectionConfig): void;
147
+ /** @internal Unregister a named connection IF it still points at `connection` (no close). */
41
148
  export declare function unregisterConnection(name: string, connection: AsyncDatabaseConnection): void;
42
- /** @internal Resolve a named connection (for `BaseModel.connection`), or `undefined`. */
149
+ /** @internal Resolve a live named connection (for `BaseModel.connection`), or `undefined`. */
43
150
  export declare function getConnection(name: string): AsyncDatabaseConnection | undefined;
151
+ /** @internal The shared connection manager (for the AtlasProvider lifecycle-event bridge). */
152
+ export declare function connectionManager(): ConnectionManager;
153
+ /** Build a {@link DbService} over a resolver that yields the live connection. */
154
+ export declare function createDbService(resolve: () => AsyncDatabaseConnection, readOnly?: boolean): DbService;
44
155
  declare const db: DbService;
45
156
  export default db;
46
157
  //# sourceMappingURL=db.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/services/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAElD,mGAAmG;AACnG,MAAM,WAAW,SAAU,SAAQ,uBAAuB;IACzD;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;CAC7C;AAID,8DAA8D;AAC9D,wBAAgB,KAAK,CAAC,UAAU,EAAE,uBAAuB,GAAG,IAAI,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,UAAU,EAAE,uBAAuB,GAAG,IAAI,CAEjE;AAED,8DAA8D;AAC9D,wBAAgB,KAAK,IAAI,uBAAuB,GAAG,SAAS,CAE3D;AAOD,2FAA2F;AAC3F,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,uBAAuB,GACjC,IAAI,CAEN;AAED,kFAAkF;AAClF,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,uBAAuB,GACjC,IAAI,CAEN;AAED,yFAAyF;AACzF,wBAAgB,aAAa,CAC5B,IAAI,EAAE,MAAM,GACV,uBAAuB,GAAG,SAAS,CAErC;AAED,QAAA,MAAM,EAAE,EAAE,SAiBR,CAAC;AAEH,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/services/db.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,11 @@
12
12
  * swap in a custom `AsyncDatabaseConnection` through the provider's
13
13
  * container hooks).
14
14
  */
15
+ import { ConnectionManager } from "../ConnectionManager.js";
16
+ import { DatabaseQueryBuilder, } from "../query/DatabaseQueryBuilder.js";
15
17
  import { RawSql } from "../query/QueryBuilder.js";
18
+ import { RawQueryBuilder, resolveRawBindings, } from "../query/RawQueryBuilder.js";
19
+ import { truncateAll } from "../testing/DatabaseCleanup.js";
16
20
  let instance;
17
21
  /** @internal Bind the singleton (called by AtlasProvider). */
18
22
  export function setDb(connection) {
@@ -32,38 +36,190 @@ export function clearDb(connection) {
32
36
  export function getDb() {
33
37
  return instance;
34
38
  }
35
- // Named-connection registry backs `BaseModel.connection = 'analytics'` so a
36
- // model can resolve a non-default connection from a plain import (AdonisJS
37
- // `static connection`). Populated by AtlasProvider for every opened connection.
38
- const namedConnections = new Map();
39
- /** @internal Register a named connection (called by AtlasProvider.boot per connection). */
40
- export function registerConnection(name, connection) {
41
- namedConnections.set(name, connection);
39
+ // The shared connection manager (Lucid `db.manager`) the single owner of named
40
+ // connections. Backs `BaseModel.connection = 'analytics'` so a model resolves a
41
+ // non-default connection from a plain import (AdonisJS `static connection`).
42
+ const manager = new ConnectionManager();
43
+ /**
44
+ * @internal Register an already-open named connection (called by AtlasProvider,
45
+ * which opens connections itself). Records the config on the node too.
46
+ */
47
+ export function registerConnection(name, connection, config = {}) {
48
+ manager.register(name, config, connection);
42
49
  }
43
- /** @internal Unregister a named connection IF it still points at `connection`. */
50
+ /** @internal Unregister a named connection IF it still points at `connection` (no close). */
44
51
  export function unregisterConnection(name, connection) {
45
- if (namedConnections.get(name) === connection)
46
- namedConnections.delete(name);
52
+ manager.deregister(name, connection);
47
53
  }
48
- /** @internal Resolve a named connection (for `BaseModel.connection`), or `undefined`. */
54
+ /** @internal Resolve a live named connection (for `BaseModel.connection`), or `undefined`. */
49
55
  export function getConnection(name) {
50
- return namedConnections.get(name);
56
+ return manager.connection(name);
51
57
  }
52
- const db = new Proxy({}, {
53
- get(_target, prop) {
54
- // `raw` is a pure builder (no connection needed) — available pre-boot too.
55
- if (prop === "raw") {
56
- return (sql, params = []) => new RawSql(sql, params);
57
- }
58
- if (!instance) {
59
- throw new Error("[atlas] db singleton accessed before AtlasProvider.boot() ran. " +
60
- "Check that `@c9up/atlas/provider` is listed in your reamrc.ts " +
61
- "providers and that `config/database.ts` defines at least one " +
62
- "connection.");
58
+ /** @internal The shared connection manager (for the AtlasProvider lifecycle-event bridge). */
59
+ export function connectionManager() {
60
+ return manager;
61
+ }
62
+ /**
63
+ * Coerce an advisory-lock key to the integer Postgres `pg_*_advisory_lock`
64
+ * requires. Numeric keys pass through; string keys are hashed deterministically
65
+ * (FNV-1a, 32-bit) so lock and unlock agree. Stable within a process is all that
66
+ * matters — atlas never shares a lock namespace with Knex.
67
+ */
68
+ function advisoryLockKey(key) {
69
+ if (typeof key === "number")
70
+ return Math.trunc(key);
71
+ let hash = 0x811c9dc5;
72
+ for (let i = 0; i < key.length; i++) {
73
+ hash ^= key.charCodeAt(i);
74
+ hash = Math.imul(hash, 0x01000193);
75
+ }
76
+ return hash | 0; // signed 32-bit — fits Postgres int/bigint
77
+ }
78
+ /** Validate + dialect-quote a (dot-qualified) identifier. Rejects anything unsafe. */
79
+ function quoteIdent(name, dialect) {
80
+ const q = dialect === "mysql" ? "`" : '"';
81
+ return name
82
+ .split(".")
83
+ .map((seg) => {
84
+ if (seg === "*")
85
+ return seg;
86
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(seg)) {
87
+ throw new Error(`atlas: invalid identifier segment '${seg}' in '${name}'`);
63
88
  }
64
- const value = Reflect.get(instance, prop, instance);
65
- return typeof value === "function" ? value.bind(instance) : value;
66
- },
89
+ return `${q}${seg}${q}`;
90
+ })
91
+ .join(".");
92
+ }
93
+ /** Build a {@link DbService} over a resolver that yields the live connection. */
94
+ export function createDbService(resolve, readOnly = false) {
95
+ const opts = readOnly ? { readOnly } : undefined;
96
+ // Per-call `{ mode: 'read' }` also yields a write-guarded builder, even on an
97
+ // unscoped service (Lucid `db.query({ mode: 'read' })`).
98
+ const optsFor = (options) => readOnly || options?.mode === "read" ? { readOnly: true } : undefined;
99
+ return {
100
+ query(options) {
101
+ const conn = resolve();
102
+ return new DatabaseQueryBuilder(options?.client ?? conn, conn.dialect, "", optsFor(options));
103
+ },
104
+ from(source, alias) {
105
+ const conn = resolve();
106
+ const builder = new DatabaseQueryBuilder(conn, conn.dialect, "", opts);
107
+ return typeof source === "string"
108
+ ? builder.from(source)
109
+ : builder.from(source, alias);
110
+ },
111
+ table(table) {
112
+ const conn = resolve();
113
+ return new DatabaseQueryBuilder(conn, conn.dialect, table, opts);
114
+ },
115
+ insertQuery(options) {
116
+ const conn = resolve();
117
+ return new DatabaseQueryBuilder(options?.client ?? conn, conn.dialect, "", optsFor(options));
118
+ },
119
+ rawQuery(sql, bindings = []) {
120
+ const conn = resolve();
121
+ return new RawQueryBuilder(conn, conn.dialect, sql, bindings);
122
+ },
123
+ connection(name, connOptions) {
124
+ // No name → the default connection's service (Lucid `db.connection()`).
125
+ if (name === undefined) {
126
+ return createDbService(resolve, connOptions?.mode === "read");
127
+ }
128
+ return createDbService(() => {
129
+ const conn = getConnection(name);
130
+ if (!conn) {
131
+ throw new Error(`[atlas] no connection registered under '${name}'. Is it in config/database.ts connections?`);
132
+ }
133
+ return conn;
134
+ }, connOptions?.mode === "read");
135
+ },
136
+ modelQuery(model) {
137
+ return model.query();
138
+ },
139
+ raw(sql, params = []) {
140
+ // Resolve `??`/named bindings only when present, so the common
141
+ // positional/no-binding path (and Postgres `::casts`) is untouched.
142
+ const hasNamed = !Array.isArray(params);
143
+ const hasIdent = typeof sql === "string" && sql.includes("??");
144
+ if (!hasNamed && !hasIdent) {
145
+ return new RawSql(sql, params);
146
+ }
147
+ const resolved = resolveRawBindings(sql, params, resolve().dialect);
148
+ return new RawSql(resolved.sql, resolved.params);
149
+ },
150
+ ref(column) {
151
+ return new RawSql(quoteIdent(column, resolve().dialect), []);
152
+ },
153
+ async truncate(table, cascade) {
154
+ const conn = resolve();
155
+ const t = quoteIdent(table, conn.dialect);
156
+ // SQLite has no TRUNCATE — DELETE clears the table (Lucid does the same).
157
+ const sql = conn.dialect === "sqlite"
158
+ ? `DELETE FROM ${t}`
159
+ : conn.dialect === "postgres"
160
+ ? `TRUNCATE TABLE ${t}${cascade ? " CASCADE" : ""}`
161
+ : `TRUNCATE TABLE ${t}`;
162
+ await conn.execute(sql, []);
163
+ },
164
+ truncateAllTables(ignoreTables = []) {
165
+ return truncateAll(resolve(), ignoreTables);
166
+ },
167
+ async getAdvisoryLock(key) {
168
+ const conn = resolve();
169
+ if (conn.dialect === "sqlite") {
170
+ throw new Error("[atlas] advisory locks are not supported on SQLite (Postgres/MySQL only).");
171
+ }
172
+ if (conn.dialect === "postgres") {
173
+ const rows = await conn.query("SELECT pg_try_advisory_lock($1) AS locked", [advisoryLockKey(key)]);
174
+ return Boolean(rows[0]?.locked);
175
+ }
176
+ // MySQL: GET_LOCK(name, 0) → non-blocking try (1 acquired, 0 busy).
177
+ const rows = await conn.query("SELECT GET_LOCK(?, 0) AS locked", [String(key)]);
178
+ return Number(rows[0]?.locked) === 1;
179
+ },
180
+ async releaseAdvisoryLock(key) {
181
+ const conn = resolve();
182
+ if (conn.dialect === "sqlite") {
183
+ throw new Error("[atlas] advisory locks are not supported on SQLite (Postgres/MySQL only).");
184
+ }
185
+ if (conn.dialect === "postgres") {
186
+ const rows = await conn.query("SELECT pg_advisory_unlock($1) AS released", [advisoryLockKey(key)]);
187
+ return Boolean(rows[0]?.released);
188
+ }
189
+ const rows = await conn.query("SELECT RELEASE_LOCK(?) AS released", [String(key)]);
190
+ return Number(rows[0]?.released) === 1;
191
+ },
192
+ get manager() {
193
+ return manager;
194
+ },
195
+ execute(sql, params) {
196
+ return resolve().execute(sql, params);
197
+ },
198
+ get transaction() {
199
+ return resolve().transaction?.bind(resolve());
200
+ },
201
+ runInTransaction(batch) {
202
+ return resolve().runInTransaction(batch);
203
+ },
204
+ get dialect() {
205
+ return resolve().dialect;
206
+ },
207
+ ping() {
208
+ return resolve().ping();
209
+ },
210
+ close() {
211
+ return resolve().close();
212
+ },
213
+ };
214
+ }
215
+ const db = createDbService(() => {
216
+ if (!instance) {
217
+ throw new Error("[atlas] db singleton accessed before AtlasProvider.boot() ran. " +
218
+ "Check that `@c9up/atlas/provider` is listed in your reamrc.ts " +
219
+ "providers and that `config/database.ts` defines at least one " +
220
+ "connection.");
221
+ }
222
+ return instance;
67
223
  });
68
224
  export default db;
69
225
  //# sourceMappingURL=db.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/services/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAalD,IAAI,QAA6C,CAAC;AAElD,8DAA8D;AAC9D,MAAM,UAAU,KAAK,CAAC,UAAmC;IACxD,QAAQ,GAAG,UAAU,CAAC;AACvB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,UAAmC;IAC1D,IAAI,QAAQ,KAAK,UAAU;QAAE,QAAQ,GAAG,SAAS,CAAC;AACnD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,KAAK;IACpB,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,2EAA2E;AAC3E,gFAAgF;AAChF,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAmC,CAAC;AAEpE,2FAA2F;AAC3F,MAAM,UAAU,kBAAkB,CACjC,IAAY,EACZ,UAAmC;IAEnC,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,oBAAoB,CACnC,IAAY,EACZ,UAAmC;IAEnC,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,UAAU;QAAE,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC9E,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,aAAa,CAC5B,IAAY;IAEZ,OAAO,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,EAAE,GAAc,IAAI,KAAK,CAAC,EAAe,EAAE;IAChD,GAAG,CAAC,OAAO,EAAE,IAAI;QAChB,2EAA2E;QAC3E,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACpB,OAAO,CAAC,GAAW,EAAE,SAAoB,EAAE,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACd,iEAAiE;gBAChE,gEAAgE;gBAChE,+DAA+D;gBAC/D,aAAa,CACd,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACpD,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,CAAC;CACD,CAAC,CAAC;AAEH,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/services/db.ts"],"names":[],"mappings":"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"}
@@ -4,19 +4,42 @@
4
4
  * @implements MISS-19
5
5
  */
6
6
  import type { AsyncDatabaseConnection } from "../adapters/NapiDbAdapter.js";
7
+ import type { TransactionClient } from "../Transaction.js";
8
+ /** What {@link useTransaction} hands back: the pinned trx plus its teardown. */
9
+ export interface TestTransaction {
10
+ /**
11
+ * The interactive transaction, pinned to ONE pooled connection. Run every
12
+ * query the test makes through THIS handle (`trx.query` / `trx.execute`, or
13
+ * `repo.useTransaction(trx)`), never the pooled `db` — that is what makes the
14
+ * rollback isolate the test.
15
+ */
16
+ trx: TransactionClient;
17
+ /** Roll everything the test did back and return the connection to the pool. */
18
+ rollback: () => Promise<void>;
19
+ }
7
20
  /**
8
- * Wrap a test in a savepoint that is rolled back after.
21
+ * Isolate a test by running it inside a transaction that is rolled back after
22
+ * (Adonis Lucid parity — Lucid's tests use `db.transaction()` the same way).
23
+ *
24
+ * The earlier implementation issued `SAVEPOINT` / `ROLLBACK` through the pooled
25
+ * `db`, so with `poolMax > 1` the savepoint and its rollback — and the test's
26
+ * own queries — could each land on a DIFFERENT pooled connection, and the
27
+ * "isolation" silently did nothing. This pins a single interactive transaction
28
+ * instead: every query on the returned `trx` runs on that one connection, and
29
+ * `rollback()` reverts them together, correctly on any pool size.
9
30
  */
10
- export declare function useTransaction(db: AsyncDatabaseConnection): Promise<() => Promise<void>>;
31
+ export declare function useTransaction(db: AsyncDatabaseConnection): Promise<TestTransaction>;
11
32
  /**
12
33
  * Empty every user table (leaves `ream_*` framework tables and dialect
13
34
  * internals alone). Works on all three dialects — the table list comes from the
14
35
  * shared dialect-aware catalog helper, not a SQLite-only `sqlite_master` query.
15
36
  *
16
37
  * Foreign keys are suspended for the duration so the delete order doesn't
17
- * matter, and restored even if a statement throws. The row removal itself goes
18
- * through the Rust compiler (`DELETE` cross-dialect and transaction-friendly,
19
- * unlike `TRUNCATE` which auto-commits on MySQL).
38
+ * matter. The FK toggle and every DELETE run on ONE pinned connection (via
39
+ * `runWithoutForeignKeys` `runInTransaction`), so a connection pool can't
40
+ * scatter the connection-local `PRAGMA`/`SET` away from the deletes. The row
41
+ * removal goes through the Rust compiler (`DELETE` — cross-dialect, unlike
42
+ * `TRUNCATE` which auto-commits on MySQL).
20
43
  */
21
- export declare function truncateAll(db: AsyncDatabaseConnection): Promise<void>;
44
+ export declare function truncateAll(db: AsyncDatabaseConnection, ignoreTables?: readonly string[]): Promise<void>;
22
45
  //# sourceMappingURL=DatabaseCleanup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DatabaseCleanup.d.ts","sourceRoot":"","sources":["../../src/testing/DatabaseCleanup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAI5E;;GAEG;AACH,wBAAsB,cAAc,CACnC,EAAE,EAAE,uBAAuB,GACzB,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAM9B;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5E"}
1
+ {"version":3,"file":"DatabaseCleanup.d.ts","sourceRoot":"","sources":["../../src/testing/DatabaseCleanup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAI5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC/B;;;;;OAKG;IACH,GAAG,EAAE,iBAAiB,CAAC;IACvB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CACnC,EAAE,EAAE,uBAAuB,GACzB,OAAO,CAAC,eAAe,CAAC,CAc1B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAChC,EAAE,EAAE,uBAAuB,EAC3B,YAAY,GAAE,SAAS,MAAM,EAAO,GAClC,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -3,17 +3,30 @@
3
3
  *
4
4
  * @implements MISS-19
5
5
  */
6
+ import { AtlasError } from "../errors.js";
6
7
  import { compileStatementNative } from "../query/native.js";
7
- import { listUserTables, withoutForeignKeys } from "../schema/catalog.js";
8
+ import { listUserTables, runWithoutForeignKeys } from "../schema/catalog.js";
8
9
  /**
9
- * Wrap a test in a savepoint that is rolled back after.
10
+ * Isolate a test by running it inside a transaction that is rolled back after
11
+ * (Adonis Lucid parity — Lucid's tests use `db.transaction()` the same way).
12
+ *
13
+ * The earlier implementation issued `SAVEPOINT` / `ROLLBACK` through the pooled
14
+ * `db`, so with `poolMax > 1` the savepoint and its rollback — and the test's
15
+ * own queries — could each land on a DIFFERENT pooled connection, and the
16
+ * "isolation" silently did nothing. This pins a single interactive transaction
17
+ * instead: every query on the returned `trx` runs on that one connection, and
18
+ * `rollback()` reverts them together, correctly on any pool size.
10
19
  */
11
20
  export async function useTransaction(db) {
12
- await db.execute("SAVEPOINT test_savepoint");
13
- return async () => {
14
- await db.execute("ROLLBACK TO SAVEPOINT test_savepoint");
15
- await db.execute("RELEASE SAVEPOINT test_savepoint");
16
- };
21
+ if (typeof db.transaction !== "function") {
22
+ throw new AtlasError("E_NO_INTERACTIVE_TRANSACTION", "useTransaction() needs a connection with an interactive transaction() (a real napi connection); this adapter has none.", {
23
+ hint: "Use createNapiConnection(), or drive rollback yourself if your adapter can't pin a connection.",
24
+ });
25
+ }
26
+ // Manual (callback-less) mode: a pinned TransactionClient the test drives and
27
+ // tears down via rollback() — no cross-pool savepoint scatter.
28
+ const trx = await db.transaction();
29
+ return { trx, rollback: () => trx.rollback() };
17
30
  }
18
31
  /**
19
32
  * Empty every user table (leaves `ream_*` framework tables and dialect
@@ -21,22 +34,36 @@ export async function useTransaction(db) {
21
34
  * shared dialect-aware catalog helper, not a SQLite-only `sqlite_master` query.
22
35
  *
23
36
  * Foreign keys are suspended for the duration so the delete order doesn't
24
- * matter, and restored even if a statement throws. The row removal itself goes
25
- * through the Rust compiler (`DELETE` cross-dialect and transaction-friendly,
26
- * unlike `TRUNCATE` which auto-commits on MySQL).
37
+ * matter. The FK toggle and every DELETE run on ONE pinned connection (via
38
+ * `runWithoutForeignKeys` `runInTransaction`), so a connection pool can't
39
+ * scatter the connection-local `PRAGMA`/`SET` away from the deletes. The row
40
+ * removal goes through the Rust compiler (`DELETE` — cross-dialect, unlike
41
+ * `TRUNCATE` which auto-commits on MySQL).
27
42
  */
28
- export async function truncateAll(db) {
43
+ export async function truncateAll(db, ignoreTables = []) {
29
44
  // The connection's own dialect, not the module default — correct even when
30
45
  // an app runs several connections on different engines.
31
46
  const dialect = db.dialect;
32
- const tables = await listUserTables(db, dialect);
47
+ const ignore = new Set(ignoreTables);
48
+ const tables = (await listUserTables(db, dialect)).filter((t) => !ignore.has(t));
33
49
  if (tables.length === 0)
34
50
  return;
35
- await withoutForeignKeys(db, dialect, async () => {
36
- for (const name of tables) {
37
- const compiled = compileStatementNative({ kind: "delete", table: name, wheres: [] }, dialect);
38
- await db.execute(compiled.statements[0], compiled.params);
39
- }
51
+ // Postgres: a plain DELETE respects FKs immediately (atlas FKs aren't
52
+ // DEFERRABLE), so deleting a parent before its children raises 23503 — and
53
+ // nothing orders the tables. `TRUNCATE CASCADE` is transactional on pg,
54
+ // order-independent, and needs no session-level FK toggle to leak. (Names
55
+ // come from the DB catalog; quote them for identifiers with embedded quotes.)
56
+ if (dialect === "postgres") {
57
+ const list = tables.map((t) => `"${t.replace(/"/g, '""')}"`).join(", ");
58
+ await db.execute(`TRUNCATE ${list} RESTART IDENTITY CASCADE`);
59
+ return;
60
+ }
61
+ // MySQL/SQLite: DELETE (TRUNCATE auto-commits on MySQL, breaking test
62
+ // transaction isolation), with FK suspension on ONE pinned connection.
63
+ const statements = tables.map((name) => {
64
+ const compiled = compileStatementNative({ kind: "delete", table: name, wheres: [] }, dialect);
65
+ return { sql: compiled.statements[0], params: compiled.params };
40
66
  });
67
+ await runWithoutForeignKeys(db, dialect, statements);
41
68
  }
42
69
  //# sourceMappingURL=DatabaseCleanup.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DatabaseCleanup.js","sourceRoot":"","sources":["../../src/testing/DatabaseCleanup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1E;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CACnC,EAA2B;IAE3B,MAAM,EAAE,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC7C,OAAO,KAAK,IAAI,EAAE;QACjB,MAAM,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC;QACzD,MAAM,EAAE,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAA2B;IAC5D,2EAA2E;IAC3E,wDAAwD;IACxD,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACjD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAChC,MAAM,kBAAkB,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE;QAChD,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,sBAAsB,CACtC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAC3C,OAAO,CACP,CAAC;YACF,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3D,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"DatabaseCleanup.js","sourceRoot":"","sources":["../../src/testing/DatabaseCleanup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAgB7E;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CACnC,EAA2B;IAE3B,IAAI,OAAO,EAAE,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;QAC1C,MAAM,IAAI,UAAU,CACnB,8BAA8B,EAC9B,wHAAwH,EACxH;YACC,IAAI,EAAE,gGAAgG;SACtG,CACD,CAAC;IACH,CAAC;IACD,8EAA8E;IAC9E,+DAA+D;IAC/D,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC;IACnC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;AAChD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,EAA2B,EAC3B,eAAkC,EAAE;IAEpC,2EAA2E;IAC3E,wDAAwD;IACxD,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,CAAC,MAAM,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CACxD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CACrB,CAAC;IACF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEhC,sEAAsE;IACtE,2EAA2E;IAC3E,0EAA0E;IAC1E,0EAA0E;IAC1E,8EAA8E;IAC9E,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxE,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,IAAI,2BAA2B,CAAC,CAAC;QAC9D,OAAO;IACR,CAAC;IAED,sEAAsE;IACtE,uEAAuE;IACvE,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACtC,MAAM,QAAQ,GAAG,sBAAsB,CACtC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAC3C,OAAO,CACP,CAAC;QACF,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;IACjE,CAAC,CAAC,CAAC;IACH,MAAM,qBAAqB,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `db()` — a helix plugin (AdonisJS Lucid database-assertions parity) that
3
+ * injects database assertions on the test context as `ctx.db`:
4
+ *
5
+ * // tests/bootstrap.ts
6
+ * import { configure } from "@c9up/helix";
7
+ * import { db } from "@c9up/atlas/testing";
8
+ * await configure({ plugins: [db(connection)] });
9
+ *
10
+ * test("registers the user", async ({ db }) => {
11
+ * await db.assertHas("users", { email: "a@b.c" });
12
+ * await db.assertCount("users", 1);
13
+ * });
14
+ *
15
+ * Values are always bound as parameters; table/column identifiers are validated
16
+ * against a strict pattern (letters, digits, `_`, `.`) and quoted, so neither a
17
+ * value nor an identifier can inject SQL.
18
+ *
19
+ * NOTE (namespace): the AdonisJS docs expose these as `db.assert*`; the exact
20
+ * surface is re-verified against the Adonis docs when available. Model-based
21
+ * `assertModelExists`/`assertModelMissing` (entity PK metadata) are pending.
22
+ */
23
+ import type { Plugin } from "@c9up/helix";
24
+ /** The minimal connection the assertions need — a parameterized query runner. */
25
+ export interface DbConnectionLike {
26
+ query(sql: string, params?: unknown[]): Promise<Record<string, unknown>[]>;
27
+ }
28
+ /** The `ctx.db` assertion surface (AdonisJS Lucid database-assertions parity). */
29
+ export interface DbAssertions {
30
+ /** At least one row in `table` matches every column in `payload`. */
31
+ assertHas(table: string, payload: Record<string, unknown>): Promise<void>;
32
+ /** No row in `table` matches `payload`. */
33
+ assertMissing(table: string, payload: Record<string, unknown>): Promise<void>;
34
+ /** `table` has exactly `expected` rows (optionally matching `payload`). */
35
+ assertCount(table: string, expected: number, payload?: Record<string, unknown>): Promise<void>;
36
+ /** `table` has no rows at all. */
37
+ assertEmpty(table: string): Promise<void>;
38
+ }
39
+ /** Build the assertion surface bound to a connection. */
40
+ export declare function createDbAssertions(conn: DbConnectionLike): DbAssertions;
41
+ /** The `db()` helix plugin — registers {@link DbAssertions} as `ctx.db`. */
42
+ export declare function db(conn: DbConnectionLike): Plugin;
43
+ declare module "@c9up/helix" {
44
+ interface TestContext {
45
+ db: DbAssertions;
46
+ }
47
+ }
48
+ //# sourceMappingURL=DbAssertions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DbAssertions.d.ts","sourceRoot":"","sources":["../../src/testing/DbAssertions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,iFAAiF;AACjF,MAAM,WAAW,gBAAgB;IAChC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;CAC3E;AA+BD,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC5B,qEAAqE;IACrE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,2CAA2C;IAC3C,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,2EAA2E;IAC3E,WAAW,CACV,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,kCAAkC;IAClC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,yDAAyD;AACzD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,CAkCvE;AAED,4EAA4E;AAC5E,wBAAgB,EAAE,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAKjD;AAID,OAAO,QAAQ,aAAa,CAAC;IAC5B,UAAU,WAAW;QACpB,EAAE,EAAE,YAAY,CAAC;KACjB;CACD"}