@c9up/atlas 0.1.19 → 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 (250) hide show
  1. package/README.md +63 -14
  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 +66 -7
  8. package/dist/AtlasProvider.d.ts.map +1 -1
  9. package/dist/AtlasProvider.js +205 -39
  10. package/dist/AtlasProvider.js.map +1 -1
  11. package/dist/BaseEntity.d.ts +181 -5
  12. package/dist/BaseEntity.d.ts.map +1 -1
  13. package/dist/BaseEntity.js +339 -33
  14. package/dist/BaseEntity.js.map +1 -1
  15. package/dist/BaseModel.d.ts +127 -0
  16. package/dist/BaseModel.d.ts.map +1 -0
  17. package/dist/BaseModel.js +250 -0
  18. package/dist/BaseModel.js.map +1 -0
  19. package/dist/BaseRepository.d.ts +81 -15
  20. package/dist/BaseRepository.d.ts.map +1 -1
  21. package/dist/BaseRepository.js +1433 -387
  22. package/dist/BaseRepository.js.map +1 -1
  23. package/dist/ConnectionManager.d.ts +106 -0
  24. package/dist/ConnectionManager.d.ts.map +1 -0
  25. package/dist/ConnectionManager.js +228 -0
  26. package/dist/ConnectionManager.js.map +1 -0
  27. package/dist/ModelQuery.d.ts +577 -41
  28. package/dist/ModelQuery.d.ts.map +1 -1
  29. package/dist/ModelQuery.js +2188 -291
  30. package/dist/ModelQuery.js.map +1 -1
  31. package/dist/Transaction.d.ts +71 -1
  32. package/dist/Transaction.d.ts.map +1 -1
  33. package/dist/Transaction.js +138 -24
  34. package/dist/Transaction.js.map +1 -1
  35. package/dist/adapters/NapiDbAdapter.d.ts +44 -4
  36. package/dist/adapters/NapiDbAdapter.d.ts.map +1 -1
  37. package/dist/adapters/NapiDbAdapter.js +131 -13
  38. package/dist/adapters/NapiDbAdapter.js.map +1 -1
  39. package/dist/console/contract.d.ts +62 -0
  40. package/dist/console/contract.d.ts.map +1 -0
  41. package/dist/console/contract.js +38 -0
  42. package/dist/console/contract.js.map +1 -0
  43. package/dist/console/factoryCommands.d.ts +23 -0
  44. package/dist/console/factoryCommands.d.ts.map +1 -0
  45. package/dist/console/factoryCommands.js +62 -0
  46. package/dist/console/factoryCommands.js.map +1 -0
  47. package/dist/console/migrationCommands.d.ts +78 -0
  48. package/dist/console/migrationCommands.d.ts.map +1 -0
  49. package/dist/console/migrationCommands.js +327 -0
  50. package/dist/console/migrationCommands.js.map +1 -0
  51. package/dist/console/schemaCheckCommand.d.ts +11 -17
  52. package/dist/console/schemaCheckCommand.d.ts.map +1 -1
  53. package/dist/console/schemaCheckCommand.js +21 -15
  54. package/dist/console/schemaCheckCommand.js.map +1 -1
  55. package/dist/console/schemaDumpCommand.d.ts +30 -0
  56. package/dist/console/schemaDumpCommand.d.ts.map +1 -0
  57. package/dist/console/schemaDumpCommand.js +69 -0
  58. package/dist/console/schemaDumpCommand.js.map +1 -0
  59. package/dist/console/schemaGenerateCommand.d.ts +100 -0
  60. package/dist/console/schemaGenerateCommand.d.ts.map +1 -0
  61. package/dist/console/schemaGenerateCommand.js +246 -0
  62. package/dist/console/schemaGenerateCommand.js.map +1 -0
  63. package/dist/console/seederCommands.d.ts +46 -0
  64. package/dist/console/seederCommands.d.ts.map +1 -0
  65. package/dist/console/seederCommands.js +136 -0
  66. package/dist/console/seederCommands.js.map +1 -0
  67. package/dist/decorators/entity.d.ts +50 -8
  68. package/dist/decorators/entity.d.ts.map +1 -1
  69. package/dist/decorators/entity.js +42 -2
  70. package/dist/decorators/entity.js.map +1 -1
  71. package/dist/decorators/hooks.d.ts +3 -3
  72. package/dist/decorators/hooks.d.ts.map +1 -1
  73. package/dist/decorators/hooks.js.map +1 -1
  74. package/dist/events.d.ts +69 -0
  75. package/dist/events.d.ts.map +1 -0
  76. package/dist/events.js +82 -0
  77. package/dist/events.js.map +1 -0
  78. package/dist/factories.d.ts +8 -0
  79. package/dist/factories.d.ts.map +1 -0
  80. package/dist/factories.js +8 -0
  81. package/dist/factories.js.map +1 -0
  82. package/dist/index.d.ts +15 -5
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +14 -3
  85. package/dist/index.js.map +1 -1
  86. package/dist/lucid-schema.d.ts +15 -0
  87. package/dist/lucid-schema.d.ts.map +1 -0
  88. package/dist/lucid-schema.js +16 -0
  89. package/dist/lucid-schema.js.map +1 -0
  90. package/dist/metadata-keys.d.ts +3 -2
  91. package/dist/metadata-keys.d.ts.map +1 -1
  92. package/dist/naming/NamingStrategy.d.ts +7 -0
  93. package/dist/naming/NamingStrategy.d.ts.map +1 -1
  94. package/dist/naming/NamingStrategy.js +16 -0
  95. package/dist/naming/NamingStrategy.js.map +1 -1
  96. package/dist/orm.d.ts +14 -0
  97. package/dist/orm.d.ts.map +1 -0
  98. package/dist/orm.js +14 -0
  99. package/dist/orm.js.map +1 -0
  100. package/dist/query/DatabaseQueryBuilder.d.ts +557 -0
  101. package/dist/query/DatabaseQueryBuilder.d.ts.map +1 -0
  102. package/dist/query/DatabaseQueryBuilder.js +1798 -0
  103. package/dist/query/DatabaseQueryBuilder.js.map +1 -0
  104. package/dist/query/DmlBuilder.d.ts +62 -0
  105. package/dist/query/DmlBuilder.d.ts.map +1 -0
  106. package/dist/query/DmlBuilder.js +84 -0
  107. package/dist/query/DmlBuilder.js.map +1 -0
  108. package/dist/query/QueryBuilder.d.ts +5 -0
  109. package/dist/query/QueryBuilder.d.ts.map +1 -1
  110. package/dist/query/QueryBuilder.js +7 -0
  111. package/dist/query/QueryBuilder.js.map +1 -1
  112. package/dist/query/RawQueryBuilder.d.ts +47 -0
  113. package/dist/query/RawQueryBuilder.d.ts.map +1 -0
  114. package/dist/query/RawQueryBuilder.js +138 -0
  115. package/dist/query/RawQueryBuilder.js.map +1 -0
  116. package/dist/query/interpolate.d.ts +45 -0
  117. package/dist/query/interpolate.d.ts.map +1 -0
  118. package/dist/query/interpolate.js +51 -0
  119. package/dist/query/interpolate.js.map +1 -0
  120. package/dist/query/native.d.ts +8 -0
  121. package/dist/query/native.d.ts.map +1 -1
  122. package/dist/query/native.js +14 -0
  123. package/dist/query/native.js.map +1 -1
  124. package/dist/query/operators.d.ts +4 -0
  125. package/dist/query/operators.d.ts.map +1 -0
  126. package/dist/query/operators.js +27 -0
  127. package/dist/query/operators.js.map +1 -0
  128. package/dist/schema/Migration.d.ts +50 -3
  129. package/dist/schema/Migration.d.ts.map +1 -1
  130. package/dist/schema/Migration.js +60 -24
  131. package/dist/schema/Migration.js.map +1 -1
  132. package/dist/schema/MigrationRunner.d.ts +95 -34
  133. package/dist/schema/MigrationRunner.d.ts.map +1 -1
  134. package/dist/schema/MigrationRunner.js +523 -68
  135. package/dist/schema/MigrationRunner.js.map +1 -1
  136. package/dist/schema/Schema.d.ts +114 -0
  137. package/dist/schema/Schema.d.ts.map +1 -1
  138. package/dist/schema/Schema.js +272 -3
  139. package/dist/schema/Schema.js.map +1 -1
  140. package/dist/schema/SchemaDumper.d.ts +121 -0
  141. package/dist/schema/SchemaDumper.d.ts.map +1 -0
  142. package/dist/schema/SchemaDumper.js +365 -0
  143. package/dist/schema/SchemaDumper.js.map +1 -0
  144. package/dist/schema/Seeder.d.ts +13 -0
  145. package/dist/schema/Seeder.d.ts.map +1 -1
  146. package/dist/schema/Seeder.js +28 -5
  147. package/dist/schema/Seeder.js.map +1 -1
  148. package/dist/schema/TableBuilder.d.ts +274 -16
  149. package/dist/schema/TableBuilder.d.ts.map +1 -1
  150. package/dist/schema/TableBuilder.js +656 -52
  151. package/dist/schema/TableBuilder.js.map +1 -1
  152. package/dist/schema/catalog.d.ts +71 -0
  153. package/dist/schema/catalog.d.ts.map +1 -0
  154. package/dist/schema/catalog.js +158 -0
  155. package/dist/schema/catalog.js.map +1 -0
  156. package/dist/schema/introspect.d.ts +1 -1
  157. package/dist/schema/introspect.d.ts.map +1 -1
  158. package/dist/schema/introspect.js +26 -11
  159. package/dist/schema/introspect.js.map +1 -1
  160. package/dist/schema/types.d.ts +150 -1
  161. package/dist/schema/types.d.ts.map +1 -1
  162. package/dist/schema/types.js +11 -0
  163. package/dist/schema/types.js.map +1 -1
  164. package/dist/seeders.d.ts +7 -0
  165. package/dist/seeders.d.ts.map +1 -0
  166. package/dist/seeders.js +7 -0
  167. package/dist/seeders.js.map +1 -0
  168. package/dist/services/db.d.ts +122 -5
  169. package/dist/services/db.d.ts.map +1 -1
  170. package/dist/services/db.js +187 -14
  171. package/dist/services/db.js.map +1 -1
  172. package/dist/testing/DatabaseCleanup.d.ts +33 -7
  173. package/dist/testing/DatabaseCleanup.d.ts.map +1 -1
  174. package/dist/testing/DatabaseCleanup.js +54 -24
  175. package/dist/testing/DatabaseCleanup.js.map +1 -1
  176. package/dist/testing/DbAssertions.d.ts +48 -0
  177. package/dist/testing/DbAssertions.d.ts.map +1 -0
  178. package/dist/testing/DbAssertions.js +80 -0
  179. package/dist/testing/DbAssertions.js.map +1 -0
  180. package/dist/testing/Factory.d.ts +166 -15
  181. package/dist/testing/Factory.d.ts.map +1 -1
  182. package/dist/testing/Factory.js +497 -23
  183. package/dist/testing/Factory.js.map +1 -1
  184. package/dist/testing/TestUtils.d.ts +49 -0
  185. package/dist/testing/TestUtils.d.ts.map +1 -0
  186. package/dist/testing/TestUtils.js +79 -0
  187. package/dist/testing/TestUtils.js.map +1 -0
  188. package/dist/testing/index.d.ts +3 -1
  189. package/dist/testing/index.d.ts.map +1 -1
  190. package/dist/testing/index.js +3 -1
  191. package/dist/testing/index.js.map +1 -1
  192. package/dist/types/relations.d.ts +31 -0
  193. package/dist/types/relations.d.ts.map +1 -0
  194. package/dist/types/relations.js +20 -0
  195. package/dist/types/relations.js.map +1 -0
  196. package/index.darwin-arm64.node +0 -0
  197. package/index.darwin-x64.node +0 -0
  198. package/index.linux-arm64-gnu.node +0 -0
  199. package/index.linux-x64-gnu.node +0 -0
  200. package/index.win32-x64-msvc.node +0 -0
  201. package/package.json +32 -2
  202. package/scripts/guard-publish.mjs +15 -0
  203. package/src/AtlasProvider.ts +305 -52
  204. package/src/BaseEntity.ts +460 -41
  205. package/src/BaseModel.ts +461 -0
  206. package/src/BaseRepository.ts +1710 -421
  207. package/src/ConnectionManager.ts +298 -0
  208. package/src/ModelQuery.ts +2998 -335
  209. package/src/Transaction.ts +227 -30
  210. package/src/adapters/NapiDbAdapter.ts +224 -17
  211. package/src/console/contract.ts +96 -0
  212. package/src/console/factoryCommands.ts +73 -0
  213. package/src/console/migrationCommands.ts +448 -0
  214. package/src/console/schemaCheckCommand.ts +26 -22
  215. package/src/console/schemaDumpCommand.ts +96 -0
  216. package/src/console/schemaGenerateCommand.ts +380 -0
  217. package/src/console/seederCommands.ts +174 -0
  218. package/src/decorators/entity.ts +71 -8
  219. package/src/decorators/hooks.ts +5 -3
  220. package/src/events.ts +117 -0
  221. package/src/factories.ts +10 -0
  222. package/src/index.ts +69 -3
  223. package/src/lucid-schema.ts +22 -0
  224. package/src/metadata-keys.ts +3 -2
  225. package/src/naming/NamingStrategy.ts +23 -0
  226. package/src/orm.ts +13 -0
  227. package/src/query/DatabaseQueryBuilder.ts +2724 -0
  228. package/src/query/DmlBuilder.ts +131 -0
  229. package/src/query/QueryBuilder.ts +8 -0
  230. package/src/query/RawQueryBuilder.ts +173 -0
  231. package/src/query/interpolate.ts +73 -0
  232. package/src/query/native.ts +29 -0
  233. package/src/query/operators.ts +27 -0
  234. package/src/schema/Migration.ts +71 -3
  235. package/src/schema/MigrationRunner.ts +676 -69
  236. package/src/schema/Schema.ts +359 -3
  237. package/src/schema/SchemaDumper.ts +518 -0
  238. package/src/schema/Seeder.ts +47 -10
  239. package/src/schema/TableBuilder.ts +783 -52
  240. package/src/schema/catalog.ts +236 -0
  241. package/src/schema/introspect.ts +26 -9
  242. package/src/schema/types.ts +137 -2
  243. package/src/seeders.ts +16 -0
  244. package/src/services/db.ts +361 -21
  245. package/src/testing/DatabaseCleanup.ts +78 -25
  246. package/src/testing/DbAssertions.ts +127 -0
  247. package/src/testing/Factory.ts +837 -40
  248. package/src/testing/TestUtils.ts +123 -0
  249. package/src/testing/index.ts +12 -1
  250. package/src/types/relations.ts +43 -0
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Connection manager — the AdonisJS Lucid `db.manager` surface. Owns a map of
3
+ * named {@link ConnectionNode}s (config + live connection + lifecycle state) and
4
+ * emits `connect`/`disconnect` events. `AtlasProvider` registers the connections
5
+ * it opens at boot; user code can also `add` + `connect` (or `patch`/`release`)
6
+ * connections at runtime.
7
+ */
8
+
9
+ import { EventEmitter } from "node:events";
10
+ import type { ConnectionConfig } from "./AtlasProvider.js";
11
+ import {
12
+ type AsyncDatabaseConnection,
13
+ createNapiConnection,
14
+ } from "./adapters/NapiDbAdapter.js";
15
+
16
+ /** Lifecycle state of a {@link ConnectionNode} (Lucid parity). */
17
+ export type ConnectionState =
18
+ | "registered"
19
+ | "open"
20
+ | "migrating"
21
+ | "closing"
22
+ | "closed";
23
+
24
+ /** A managed connection: its config, the live handle (once open), and its state. */
25
+ export interface ConnectionNode {
26
+ readonly name: string;
27
+ config: ConnectionConfig;
28
+ connection?: AsyncDatabaseConnection;
29
+ state: ConnectionState;
30
+ }
31
+
32
+ /** Opens a live connection from a config (Lucid's dialect client — here, napi). */
33
+ export type ConnectionFactory = (
34
+ name: string,
35
+ config: ConnectionConfig,
36
+ ) => Promise<AsyncDatabaseConnection>;
37
+
38
+ /** Default factory — opens via the Rust/NAPI driver from a {@link ConnectionConfig}. */
39
+ export async function openFromConfig(
40
+ name: string,
41
+ config: ConnectionConfig,
42
+ ): Promise<AsyncDatabaseConnection> {
43
+ const url = config.url ?? config.connection;
44
+ if (!url) {
45
+ throw new Error(
46
+ `[atlas] connection '${name}' has no URL — set 'url' (or Lucid's 'connection').`,
47
+ );
48
+ }
49
+ return createNapiConnection(
50
+ url,
51
+ config.pool?.min ?? config.poolMin ?? 1,
52
+ config.pool?.max ?? config.poolMax ?? 10,
53
+ config.pragmas,
54
+ {
55
+ retries: config.connectRetries,
56
+ backoffMs: config.connectBackoffMs,
57
+ timeoutMs: config.connectTimeoutMs,
58
+ },
59
+ { debug: config.debug ?? false, connectionName: name },
60
+ );
61
+ }
62
+
63
+ /** The Lucid `db.manager` connection manager. */
64
+ export class ConnectionManager {
65
+ readonly #nodes = new Map<string, ConnectionNode>();
66
+ readonly #events = new EventEmitter();
67
+ readonly #factory: ConnectionFactory;
68
+
69
+ constructor(factory: ConnectionFactory = openFromConfig) {
70
+ this.#factory = factory;
71
+ }
72
+
73
+ /** The node map, keyed by connection name (Lucid `manager.connections`). */
74
+ get connections(): ReadonlyMap<string, ConnectionNode> {
75
+ return this.#nodes;
76
+ }
77
+
78
+ /**
79
+ * Register a connection config WITHOUT opening it (Lucid `manager.add`).
80
+ * No-op if the name is ALREADY registered (any state) — use {@link patch} to
81
+ * replace an existing connection's config (Lucid semantics).
82
+ */
83
+ add(name: string, config: ConnectionConfig): this {
84
+ if (this.#nodes.has(name)) return this;
85
+ this.#nodes.set(name, { name, config, state: "registered" });
86
+ return this;
87
+ }
88
+
89
+ /**
90
+ * Replace a connection's config (Lucid `manager.patch`). If it is currently
91
+ * open, the live pool is disconnected in the BACKGROUND (in-flight queries
92
+ * drain) and the node returns to `registered`, so the next `connect` opens a
93
+ * fresh pool with the new config.
94
+ */
95
+ patch(name: string, config: ConnectionConfig): this {
96
+ const node = this.#nodes.get(name);
97
+ if (!node) {
98
+ this.#nodes.set(name, { name, config, state: "registered" });
99
+ return this;
100
+ }
101
+ const stale = node.connection;
102
+ node.config = config;
103
+ node.connection = undefined;
104
+ node.state = "registered";
105
+ if (stale) {
106
+ // Background disconnect — don't block patch; swallow late errors.
107
+ void stale.close().catch(() => {});
108
+ this.#events.emit("disconnect", node);
109
+ }
110
+ return this;
111
+ }
112
+
113
+ /**
114
+ * Open a connection (Lucid `manager.connect`). Idempotent — returns the live
115
+ * handle if already open. The connection must have been {@link add}ed first,
116
+ * or pass its config here.
117
+ */
118
+ async connect(
119
+ name: string,
120
+ config?: ConnectionConfig,
121
+ ): Promise<AsyncDatabaseConnection> {
122
+ let node = this.#nodes.get(name);
123
+ if (!node) {
124
+ if (!config) {
125
+ throw new Error(
126
+ `[atlas] no connection '${name}' registered — call manager.add(name, config) first.`,
127
+ );
128
+ }
129
+ node = { name, config, state: "registered" };
130
+ this.#nodes.set(name, node);
131
+ }
132
+ if (node.state === "open" && node.connection) return node.connection;
133
+ let connection: AsyncDatabaseConnection;
134
+ try {
135
+ connection = await this.#factory(name, config ?? node.config);
136
+ } catch (err) {
137
+ // Local `error` event as `(node, error)` — the AtlasProvider bridge
138
+ // re-emits it on the app emitter as Lucid's `db:connection:error`
139
+ // (`[error, node]`). Guard the emit: Node's EventEmitter throws on an
140
+ // `error` event with no listeners, which would mask the real error.
141
+ if (this.#events.listenerCount("error") > 0) {
142
+ this.#events.emit("error", node, err);
143
+ }
144
+ throw err;
145
+ }
146
+ node.connection = connection;
147
+ node.state = "open";
148
+ this.#events.emit("connect", node);
149
+ return connection;
150
+ }
151
+
152
+ /**
153
+ * @internal Register an ALREADY-OPEN connection (used by `AtlasProvider`, which
154
+ * opens connections itself with its retry/rollback logic). Node state = open.
155
+ */
156
+ register(
157
+ name: string,
158
+ config: ConnectionConfig,
159
+ connection: AsyncDatabaseConnection,
160
+ ): void {
161
+ this.#nodes.set(name, { name, config, connection, state: "open" });
162
+ this.#events.emit("connect", this.#nodes.get(name));
163
+ }
164
+
165
+ /**
166
+ * @internal Emit a connect `error` for a node (AtlasProvider opens the boot
167
+ * pools itself with its parallel/rollback logic, so its failures are surfaced
168
+ * through the manager here → `db:connection:error`). Guarded like {@link connect}.
169
+ */
170
+ reportConnectError(name: string, error: unknown): void {
171
+ const node = this.#nodes.get(name) ?? {
172
+ name,
173
+ config: {},
174
+ state: "closed" as const,
175
+ };
176
+ if (this.#events.listenerCount("error") > 0) {
177
+ this.#events.emit("error", node, error);
178
+ }
179
+ }
180
+
181
+ /** Whether a connection is registered (Lucid `manager.has`). */
182
+ has(name: string): boolean {
183
+ return this.#nodes.has(name);
184
+ }
185
+
186
+ /** The connection node, or `undefined` (Lucid `manager.get`). */
187
+ get(name: string): ConnectionNode | undefined {
188
+ return this.#nodes.get(name);
189
+ }
190
+
191
+ /** Whether the pool is active — `open` or `migrating` (Lucid `manager.isConnected`). */
192
+ isConnected(name: string): boolean {
193
+ const state = this.#nodes.get(name)?.state;
194
+ return state === "open" || state === "migrating";
195
+ }
196
+
197
+ /** The live connection handle for `name`, or `undefined` if the pool isn't active. */
198
+ connection(name: string): AsyncDatabaseConnection | undefined {
199
+ const node = this.#nodes.get(name);
200
+ return node && (node.state === "open" || node.state === "migrating")
201
+ ? node.connection
202
+ : undefined;
203
+ }
204
+
205
+ /**
206
+ * Close the connection's pool (Lucid `manager.close`). Keeps the node (state →
207
+ * `closed`) so it can be reopened; pass `release: true` to also remove the node
208
+ * entirely (equivalent to {@link release}).
209
+ */
210
+ async close(name: string, release = false): Promise<void> {
211
+ const node = this.#nodes.get(name);
212
+ if (
213
+ node?.connection &&
214
+ (node.state === "open" || node.state === "migrating")
215
+ ) {
216
+ const conn = node.connection;
217
+ node.state = "closing";
218
+ node.connection = undefined;
219
+ await conn.close();
220
+ node.state = "closed";
221
+ this.#events.emit("disconnect", node);
222
+ }
223
+ if (release) this.#nodes.delete(name);
224
+ }
225
+
226
+ /**
227
+ * Close every connection's pool (Lucid `manager.closeAll`). Pass `release: true`
228
+ * to also remove every node from the manager.
229
+ */
230
+ async closeAll(release = false): Promise<void> {
231
+ for (const name of [...this.#nodes.keys()]) {
232
+ await this.close(name, release);
233
+ }
234
+ }
235
+
236
+ /** Close and REMOVE a connection node entirely (Lucid `manager.release`). */
237
+ async release(name: string): Promise<void> {
238
+ await this.close(name, true);
239
+ }
240
+
241
+ /**
242
+ * @internal Remove a node WITHOUT closing it — the caller already closed the
243
+ * connection (e.g. `AtlasProvider.shutdown`). Ownership-guarded: only removes
244
+ * when the node still points at `connection`, so a re-registered node from a
245
+ * newer provider isn't dropped by an older one's teardown.
246
+ */
247
+ deregister(name: string, connection?: AsyncDatabaseConnection): void {
248
+ const node = this.#nodes.get(name);
249
+ if (!node) return;
250
+ if (connection && node.connection !== connection) return;
251
+ this.#nodes.delete(name);
252
+ }
253
+
254
+ /**
255
+ * Move an open connection into the `migrating` state (Lucid parity) — the pool
256
+ * stays active (`isConnected`/`connection` still resolve). Call {@link endMigrating}
257
+ * (or it's restored by the migration runner) when done.
258
+ */
259
+ markMigrating(name: string): void {
260
+ const node = this.#nodes.get(name);
261
+ if (node?.state === "open") node.state = "migrating";
262
+ }
263
+
264
+ /** Restore a `migrating` connection to `open`. */
265
+ endMigrating(name: string): void {
266
+ const node = this.#nodes.get(name);
267
+ if (node?.state === "migrating") node.state = "open";
268
+ }
269
+
270
+ /**
271
+ * Subscribe to lifecycle events (Node EventEmitter). `connect`/`disconnect`
272
+ * call the listener with the {@link ConnectionNode}; `error` calls it with
273
+ * `(node, error)`.
274
+ */
275
+ on(
276
+ event: "connect" | "disconnect" | "error",
277
+ listener: (node: ConnectionNode, error?: unknown) => void,
278
+ ): this {
279
+ this.#events.on(event, listener);
280
+ return this;
281
+ }
282
+ /** One-shot {@link on}. */
283
+ once(
284
+ event: "connect" | "disconnect" | "error",
285
+ listener: (node: ConnectionNode, error?: unknown) => void,
286
+ ): this {
287
+ this.#events.once(event, listener);
288
+ return this;
289
+ }
290
+ /** Remove a lifecycle listener. */
291
+ off(
292
+ event: "connect" | "disconnect" | "error",
293
+ listener: (node: ConnectionNode, error?: unknown) => void,
294
+ ): this {
295
+ this.#events.off(event, listener);
296
+ return this;
297
+ }
298
+ }