@hexaijs/sqlite 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,7 +28,7 @@ npm install @hexaijs/sqlite
28
28
  **Peer dependencies:**
29
29
 
30
30
  ```bash
31
- npm install @hexaijs/core sqlite sqlite3
31
+ npm install @hexaijs/core better-sqlite3
32
32
  ```
33
33
 
34
34
  ## Core Concepts
@@ -38,15 +38,11 @@ npm install @hexaijs/core sqlite sqlite3
38
38
  The `SqliteUnitOfWork` implements `UnitOfWork<Database>` from `@hexaijs/core`. It manages transaction lifecycle for a given SQLite database connection.
39
39
 
40
40
  ```typescript
41
- import { open } from "sqlite";
42
- import sqlite3 from "sqlite3";
41
+ import Database from "better-sqlite3";
43
42
  import { SqliteUnitOfWork } from "@hexaijs/sqlite";
44
43
 
45
44
  // Create an in-memory database
46
- const db = await open({
47
- filename: ":memory:",
48
- driver: sqlite3.Database,
49
- });
45
+ const db = new Database(":memory:");
50
46
 
51
47
  // Create unit of work
52
48
  const unitOfWork = new SqliteUnitOfWork(db);
@@ -61,8 +57,8 @@ Use `scope()` to define a transaction boundary:
61
57
  ```typescript
62
58
  const result = await unitOfWork.scope(async () => {
63
59
  const db = unitOfWork.getClient();
64
- await db.run("INSERT INTO orders (id, status) VALUES (?, ?)", [orderId, "pending"]);
65
- await db.run("INSERT INTO order_items (order_id, product_id) VALUES (?, ?)", [orderId, productId]);
60
+ db.prepare("INSERT INTO orders (id, status) VALUES (?, ?)").run(orderId, "pending");
61
+ db.prepare("INSERT INTO order_items (order_id, product_id) VALUES (?, ?)").run(orderId, productId);
66
62
  return { orderId };
67
63
  });
68
64
  // Transaction commits if successful
@@ -73,7 +69,7 @@ const result = await unitOfWork.scope(async () => {
73
69
  ```typescript
74
70
  /** @deprecated Use scope() instead. */
75
71
  const result = await unitOfWork.wrap(async (db) => {
76
- await db.run("INSERT INTO orders (id, status) VALUES (?, ?)", [orderId, "pending"]);
72
+ db.prepare("INSERT INTO orders (id, status) VALUES (?, ?)").run(orderId, "pending");
77
73
  return { orderId };
78
74
  });
79
75
  ```
@@ -84,7 +80,7 @@ If an error is thrown, the transaction rolls back:
84
80
  try {
85
81
  await unitOfWork.scope(async () => {
86
82
  const db = unitOfWork.getClient();
87
- await db.run("INSERT INTO orders (id, status) VALUES (?, ?)", [orderId, "pending"]);
83
+ db.prepare("INSERT INTO orders (id, status) VALUES (?, ?)").run(orderId, "pending");
88
84
  throw new Error("Something went wrong");
89
85
  });
90
86
  } catch (error) {
@@ -99,11 +95,44 @@ Within a transaction, access the database through `getClient()`:
99
95
  ```typescript
100
96
  // Inside a command handler
101
97
  const db = ctx.getUnitOfWork().getClient();
102
- await db.run("UPDATE orders SET status = ? WHERE id = ?", ["confirmed", orderId]);
98
+ db.prepare("UPDATE orders SET status = ? WHERE id = ?").run("confirmed", orderId);
103
99
  ```
104
100
 
105
101
  Note: `getClient()` throws an error if called outside of a `scope()` or `wrap()` call.
106
102
 
103
+ ### Transaction Lifecycle Hooks
104
+
105
+ Register callbacks that execute at specific points in the transaction lifecycle:
106
+
107
+ ```typescript
108
+ await unitOfWork.scope(async () => {
109
+ unitOfWork.beforeCommit(() => {
110
+ // Validate before committing
111
+ });
112
+
113
+ unitOfWork.afterCommit(() => {
114
+ // Notify after successful commit
115
+ });
116
+
117
+ unitOfWork.afterRollback(() => {
118
+ // Clean up on failure
119
+ });
120
+
121
+ const db = unitOfWork.getClient();
122
+ db.prepare("INSERT INTO orders (id, status) VALUES (?, ?)").run(orderId, "pending");
123
+ });
124
+ ```
125
+
126
+ Hooks follow the same semantics as `@hexaijs/postgres`:
127
+
128
+ | Hook | When | On failure |
129
+ |------|------|------------|
130
+ | `beforeCommit` | Before COMMIT | Transaction rolls back instead |
131
+ | `afterCommit` | After COMMIT | Best-effort (errors → `AggregateError`) |
132
+ | `afterRollback` | After ROLLBACK | Best-effort (errors → `AggregateError`) |
133
+
134
+ Hooks are scope-local and can only be registered inside an active `scope()`.
135
+
107
136
  ### Nested Transactions
108
137
 
109
138
  Nested `scope()` calls participate in the same transaction:
@@ -111,11 +140,11 @@ Nested `scope()` calls participate in the same transaction:
111
140
  ```typescript
112
141
  await unitOfWork.scope(async () => {
113
142
  const db = unitOfWork.getClient();
114
- await db.run("INSERT INTO orders (id) VALUES (?)", ["order-1"]);
143
+ db.prepare("INSERT INTO orders (id) VALUES (?)").run("order-1");
115
144
 
116
145
  await unitOfWork.scope(async () => {
117
146
  const db = unitOfWork.getClient();
118
- await db.run("INSERT INTO order_items (order_id) VALUES (?)", ["order-1"]);
147
+ db.prepare("INSERT INTO order_items (order_id) VALUES (?)").run("order-1");
119
148
  });
120
149
  // Both inserts are in the same transaction
121
150
  });
@@ -128,11 +157,11 @@ If any nested call throws, the entire transaction rolls back:
128
157
  try {
129
158
  await unitOfWork.scope(async () => {
130
159
  const db = unitOfWork.getClient();
131
- await db.run("INSERT INTO orders (id) VALUES (?)", ["order-1"]);
160
+ db.prepare("INSERT INTO orders (id) VALUES (?)").run("order-1");
132
161
 
133
162
  await unitOfWork.scope(async () => {
134
163
  const db = unitOfWork.getClient();
135
- await db.run("INSERT INTO order_items (order_id) VALUES (?)", ["order-1"]);
164
+ db.prepare("INSERT INTO order_items (order_id) VALUES (?)").run("order-1");
136
165
  throw new Error("Nested failure");
137
166
  });
138
167
  });
@@ -148,7 +177,7 @@ try {
148
177
  Use the test utilities for fast, isolated integration tests:
149
178
 
150
179
  ```typescript
151
- import type { Database } from "sqlite";
180
+ import type { Database } from "better-sqlite3";
152
181
  import { SqliteUnitOfWork } from "@hexaijs/sqlite";
153
182
  import { getSqliteConnection } from "@hexaijs/sqlite/test";
154
183
 
@@ -156,12 +185,12 @@ describe("OrderRepository", () => {
156
185
  let db: Database;
157
186
  let unitOfWork: SqliteUnitOfWork;
158
187
 
159
- beforeEach(async () => {
188
+ beforeEach(() => {
160
189
  // Create fresh in-memory database
161
- db = await getSqliteConnection();
190
+ db = getSqliteConnection();
162
191
 
163
192
  // Create schema
164
- await db.run(`
193
+ db.exec(`
165
194
  CREATE TABLE orders (
166
195
  id TEXT PRIMARY KEY,
167
196
  status TEXT NOT NULL
@@ -171,17 +200,17 @@ describe("OrderRepository", () => {
171
200
  unitOfWork = new SqliteUnitOfWork(db);
172
201
  });
173
202
 
174
- afterEach(async () => {
175
- await db.close();
203
+ afterEach(() => {
204
+ db.close();
176
205
  });
177
206
 
178
207
  it("should persist orders", async () => {
179
208
  await unitOfWork.scope(async () => {
180
209
  const db = unitOfWork.getClient();
181
- await db.run("INSERT INTO orders (id, status) VALUES (?, ?)", ["order-1", "pending"]);
210
+ db.prepare("INSERT INTO orders (id, status) VALUES (?, ?)").run("order-1", "pending");
182
211
  });
183
212
 
184
- const result = await db.get("SELECT * FROM orders WHERE id = ?", ["order-1"]);
213
+ const result = db.prepare("SELECT * FROM orders WHERE id = ?").get("order-1") as any;
185
214
  expect(result.status).toBe("pending");
186
215
  });
187
216
  });
@@ -218,7 +247,7 @@ interface OrderMemento {
218
247
  }
219
248
 
220
249
  // Create repository
221
- const db = await getSqliteConnection();
250
+ const db = getSqliteConnection();
222
251
  const orderRepository = new SqliteRepositoryForTest<Order, OrderMemento>(db, {
223
252
  namespace: "orders",
224
253
  hydrate: (m) => new Order(new OrderId(m.id), m.status),
@@ -242,7 +271,7 @@ For scenarios requiring persistence across test runs or debugging:
242
271
  import { getSqliteConnection } from "@hexaijs/sqlite/test";
243
272
 
244
273
  // File-based database instead of in-memory
245
- const db = await getSqliteConnection("./test-database.sqlite");
274
+ const db = getSqliteConnection("./test-database.sqlite");
246
275
  ```
247
276
 
248
277
  ## API Highlights
package/dist/index.d.ts CHANGED
@@ -1,13 +1,17 @@
1
- import { Database } from 'sqlite';
2
- import { UnitOfWork } from '@hexaijs/core';
1
+ import { Database } from 'better-sqlite3';
2
+ import { UnitOfWork, TransactionHook } from '@hexaijs/core';
3
3
 
4
4
  declare class SqliteUnitOfWork implements UnitOfWork<Database> {
5
5
  private db;
6
6
  private static transactions;
7
7
  constructor(db: Database);
8
8
  getClient(): Database;
9
+ beforeCommit(hook: TransactionHook): void;
10
+ afterCommit(hook: TransactionHook): void;
11
+ afterRollback(hook: TransactionHook): void;
9
12
  scope<T>(fn: () => Promise<T>): Promise<T>;
10
13
  wrap<T>(fn: (client: Database) => Promise<T>): Promise<T>;
14
+ private getRequiredState;
11
15
  }
12
16
 
13
17
  export { SqliteUnitOfWork };
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { TransactionHooks } from '@hexaijs/core';
2
+
1
3
  // src/sqlite-unit-of-work.ts
2
4
  var SqliteUnitOfWork = class _SqliteUnitOfWork {
3
5
  constructor(db) {
@@ -5,7 +7,8 @@ var SqliteUnitOfWork = class _SqliteUnitOfWork {
5
7
  if (!_SqliteUnitOfWork.transactions.has(db)) {
6
8
  _SqliteUnitOfWork.transactions.set(db, {
7
9
  level: 0,
8
- aborted: false
10
+ aborted: false,
11
+ hooks: new TransactionHooks()
9
12
  });
10
13
  }
11
14
  }
@@ -17,31 +20,70 @@ var SqliteUnitOfWork = class _SqliteUnitOfWork {
17
20
  }
18
21
  return this.db;
19
22
  }
23
+ beforeCommit(hook) {
24
+ const current = this.getRequiredState("beforeCommit");
25
+ current.hooks.addBeforeCommit(hook);
26
+ }
27
+ afterCommit(hook) {
28
+ const current = this.getRequiredState("afterCommit");
29
+ current.hooks.addAfterCommit(hook);
30
+ }
31
+ afterRollback(hook) {
32
+ const current = this.getRequiredState("afterRollback");
33
+ current.hooks.addAfterRollback(hook);
34
+ }
20
35
  async scope(fn) {
21
36
  return this.wrap(fn);
22
37
  }
23
38
  async wrap(fn) {
24
39
  const current = _SqliteUnitOfWork.transactions.get(this.db);
25
40
  if (++current.level === 1) {
26
- await this.db.run("BEGIN TRANSACTION");
41
+ this.db.exec("BEGIN TRANSACTION");
27
42
  }
43
+ let abortError;
28
44
  try {
29
45
  return await fn(this.db);
30
46
  } catch (e) {
31
47
  if (!current.aborted) {
32
48
  current.aborted = true;
33
49
  }
50
+ abortError = e;
34
51
  throw e;
35
52
  } finally {
36
53
  if (--current.level === 0) {
37
- if (current.aborted) {
38
- await this.db.run("ROLLBACK");
54
+ const hooks = current.hooks;
55
+ const wasAborted = current.aborted;
56
+ current.hooks = new TransactionHooks();
57
+ current.aborted = false;
58
+ if (wasAborted) {
59
+ await hooks.executeRollback(
60
+ async () => {
61
+ this.db.exec("ROLLBACK");
62
+ },
63
+ abortError
64
+ );
39
65
  } else {
40
- await this.db.run("COMMIT");
66
+ await hooks.executeCommit(
67
+ async () => {
68
+ this.db.exec("COMMIT");
69
+ },
70
+ async () => {
71
+ this.db.exec("ROLLBACK");
72
+ }
73
+ );
41
74
  }
42
75
  }
43
76
  }
44
77
  }
78
+ getRequiredState(hookName) {
79
+ const current = _SqliteUnitOfWork.transactions.get(this.db);
80
+ if (!current || current.level === 0) {
81
+ throw new Error(
82
+ `Cannot register ${hookName} hook outside of a transaction scope`
83
+ );
84
+ }
85
+ return current;
86
+ }
45
87
  };
46
88
 
47
89
  export { SqliteUnitOfWork };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sqlite-unit-of-work.ts"],"names":[],"mappings":";AAIO,IAAM,gBAAA,GAAN,MAAM,iBAAA,CAAiD;AAAA,EAS1D,YAAoB,EAAA,EAAc;AAAd,IAAA,IAAA,CAAA,EAAA,GAAA,EAAA;AAChB,IAAA,IAAI,CAAC,iBAAA,CAAiB,YAAA,CAAa,GAAA,CAAI,EAAE,CAAA,EAAG;AACxC,MAAA,iBAAA,CAAiB,YAAA,CAAa,IAAI,EAAA,EAAI;AAAA,QAClC,KAAA,EAAO,CAAA;AAAA,QACP,OAAA,EAAS;AAAA,OACZ,CAAA;AAAA,IACL;AAAA,EACJ;AAAA,EAfA,OAAe,YAAA,mBAAe,IAAI,OAAA,EAMhC;AAAA,EAWF,SAAA,GAAsB;AAClB,IAAA,MAAM,OAAA,GAAU,iBAAA,CAAiB,YAAA,CAAa,GAAA,CAAI,KAAK,EAAE,CAAA;AACzD,IAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,KAAA,KAAU,CAAA,EAAG;AACjC,MAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,IAC9C;AACA,IAAA,OAAO,IAAA,CAAK,EAAA;AAAA,EAChB;AAAA,EAEA,MAAM,MAAS,EAAA,EAAkC;AAC7C,IAAA,OAAO,IAAA,CAAK,KAAK,EAAE,CAAA;AAAA,EACvB;AAAA,EAEA,MAAM,KAAQ,EAAA,EAAkD;AAC5D,IAAA,MAAM,OAAA,GAAU,iBAAA,CAAiB,YAAA,CAAa,GAAA,CAAI,KAAK,EAAE,CAAA;AACzD,IAAA,IAAI,EAAE,OAAA,CAAQ,KAAA,KAAU,CAAA,EAAG;AACvB,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,GAAA,CAAI,mBAAmB,CAAA;AAAA,IACzC;AAEA,IAAA,IAAI;AACA,MAAA,OAAO,MAAM,EAAA,CAAG,IAAA,CAAK,EAAE,CAAA;AAAA,IAC3B,SAAS,CAAA,EAAG;AACR,MAAA,IAAI,CAAC,QAAQ,OAAA,EAAS;AAClB,QAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAAA,MACtB;AAEA,MAAA,MAAM,CAAA;AAAA,IACV,CAAA,SAAE;AACE,MAAA,IAAI,EAAE,OAAA,CAAQ,KAAA,KAAU,CAAA,EAAG;AACvB,QAAA,IAAI,QAAQ,OAAA,EAAS;AACjB,UAAA,MAAM,IAAA,CAAK,EAAA,CAAG,GAAA,CAAI,UAAU,CAAA;AAAA,QAChC,CAAA,MAAO;AACH,UAAA,MAAM,IAAA,CAAK,EAAA,CAAG,GAAA,CAAI,QAAQ,CAAA;AAAA,QAC9B;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ","file":"index.js","sourcesContent":["import type { Database } from \"sqlite\";\n\nimport { UnitOfWork } from \"@hexaijs/core\";\n\nexport class SqliteUnitOfWork implements UnitOfWork<Database> {\n private static transactions = new WeakMap<\n Database,\n {\n level: number;\n aborted: boolean;\n }\n >();\n\n constructor(private db: Database) {\n if (!SqliteUnitOfWork.transactions.has(db)) {\n SqliteUnitOfWork.transactions.set(db, {\n level: 0,\n aborted: false,\n });\n }\n }\n\n getClient(): Database {\n const current = SqliteUnitOfWork.transactions.get(this.db);\n if (!current || current.level === 0) {\n throw new Error(\"No transaction is active\");\n }\n return this.db;\n }\n\n async scope<T>(fn: () => Promise<T>): Promise<T> {\n return this.wrap(fn);\n }\n\n async wrap<T>(fn: (client: Database) => Promise<T>): Promise<T> {\n const current = SqliteUnitOfWork.transactions.get(this.db)!;\n if (++current.level === 1) {\n await this.db.run(\"BEGIN TRANSACTION\");\n }\n\n try {\n return await fn(this.db);\n } catch (e) {\n if (!current.aborted) {\n current.aborted = true;\n }\n\n throw e;\n } finally {\n if (--current.level === 0) {\n if (current.aborted) {\n await this.db.run(\"ROLLBACK\");\n } else {\n await this.db.run(\"COMMIT\");\n }\n }\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/sqlite-unit-of-work.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Database } from \"better-sqlite3\";\n\nimport { TransactionHooks, UnitOfWork } from \"@hexaijs/core\";\nimport type { TransactionHook } from \"@hexaijs/core\";\n\nexport class SqliteUnitOfWork implements UnitOfWork<Database> {\n private static transactions = new WeakMap<\n Database,\n {\n level: number;\n aborted: boolean;\n hooks: TransactionHooks;\n }\n >();\n\n constructor(private db: Database) {\n if (!SqliteUnitOfWork.transactions.has(db)) {\n SqliteUnitOfWork.transactions.set(db, {\n level: 0,\n aborted: false,\n hooks: new TransactionHooks(),\n });\n }\n }\n\n getClient(): Database {\n const current = SqliteUnitOfWork.transactions.get(this.db);\n if (!current || current.level === 0) {\n throw new Error(\"No transaction is active\");\n }\n return this.db;\n }\n\n beforeCommit(hook: TransactionHook): void {\n const current = this.getRequiredState(\"beforeCommit\");\n current.hooks.addBeforeCommit(hook);\n }\n\n afterCommit(hook: TransactionHook): void {\n const current = this.getRequiredState(\"afterCommit\");\n current.hooks.addAfterCommit(hook);\n }\n\n afterRollback(hook: TransactionHook): void {\n const current = this.getRequiredState(\"afterRollback\");\n current.hooks.addAfterRollback(hook);\n }\n\n async scope<T>(fn: () => Promise<T>): Promise<T> {\n return this.wrap(fn);\n }\n\n async wrap<T>(fn: (client: Database) => Promise<T>): Promise<T> {\n const current = SqliteUnitOfWork.transactions.get(this.db)!;\n if (++current.level === 1) {\n this.db.exec(\"BEGIN TRANSACTION\");\n }\n\n let abortError: unknown;\n try {\n return await fn(this.db);\n } catch (e) {\n if (!current.aborted) {\n current.aborted = true;\n }\n abortError = e;\n\n throw e;\n } finally {\n if (--current.level === 0) {\n const hooks = current.hooks;\n const wasAborted = current.aborted;\n\n current.hooks = new TransactionHooks();\n current.aborted = false;\n\n if (wasAborted) {\n await hooks.executeRollback(\n async () => { this.db.exec(\"ROLLBACK\"); },\n abortError\n );\n } else {\n await hooks.executeCommit(\n async () => { this.db.exec(\"COMMIT\"); },\n async () => { this.db.exec(\"ROLLBACK\"); }\n );\n }\n }\n }\n }\n\n private getRequiredState(hookName: string) {\n const current = SqliteUnitOfWork.transactions.get(this.db);\n if (!current || current.level === 0) {\n throw new Error(\n `Cannot register ${hookName} hook outside of a transaction scope`\n );\n }\n return current;\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Database } from 'sqlite';
1
+ import { Database } from 'better-sqlite3';
2
2
  import { Identifiable, Repository, IdOf } from '@hexaijs/core';
3
3
 
4
4
  declare class SqliteRepositoryForTest<E extends Identifiable<any>, M> implements Repository<E> {
@@ -15,9 +15,9 @@ declare class SqliteRepositoryForTest<E extends Identifiable<any>, M> implements
15
15
  add(entity: E): Promise<void>;
16
16
  update(entity: E): Promise<void>;
17
17
  count(): Promise<number>;
18
- protected ensureTableExists(): Promise<void>;
18
+ protected ensureTableExists(): void;
19
19
  }
20
20
 
21
- declare function getSqliteConnection(filename?: string): Promise<Database>;
21
+ declare function getSqliteConnection(filename?: string): Database;
22
22
 
23
23
  export { SqliteRepositoryForTest, getSqliteConnection };
@@ -1,4 +1,5 @@
1
1
  import { ObjectNotFoundError, DuplicateObjectError } from '@hexaijs/core';
2
+ import Database from 'better-sqlite3';
2
3
 
3
4
  // src/test/sqlite-repository-for-test.ts
4
5
  var SqliteRepositoryForTest = class {
@@ -16,11 +17,10 @@ var SqliteRepositoryForTest = class {
16
17
  hydrate;
17
18
  dehydrate;
18
19
  async get(id) {
19
- await this.ensureTableExists();
20
- const row = await this.db.get(
21
- `SELECT * FROM ${this.namespace} WHERE id = ?`,
22
- id.getValue()
23
- );
20
+ this.ensureTableExists();
21
+ const row = this.db.prepare(
22
+ `SELECT * FROM ${this.namespace} WHERE id = ?`
23
+ ).get(id.getValue());
24
24
  if (!row) {
25
25
  throw new ObjectNotFoundError(
26
26
  `entity with id '${id.getValue()}' not found`
@@ -29,11 +29,12 @@ var SqliteRepositoryForTest = class {
29
29
  return this.hydrate(JSON.parse(row.data));
30
30
  }
31
31
  async add(entity) {
32
- await this.ensureTableExists();
32
+ this.ensureTableExists();
33
33
  try {
34
- await this.db.run(
34
+ this.db.prepare(
35
35
  `INSERT INTO ${this.namespace} (id, data)
36
- VALUES (?, ?)`,
36
+ VALUES (?, ?)`
37
+ ).run(
37
38
  entity.getId().getValue(),
38
39
  JSON.stringify(this.dehydrate(entity))
39
40
  );
@@ -47,11 +48,12 @@ var SqliteRepositoryForTest = class {
47
48
  }
48
49
  }
49
50
  async update(entity) {
50
- await this.ensureTableExists();
51
- const result = await this.db.run(
51
+ this.ensureTableExists();
52
+ const result = this.db.prepare(
52
53
  `UPDATE ${this.namespace}
53
54
  SET data = ?
54
- WHERE id = ?`,
55
+ WHERE id = ?`
56
+ ).run(
55
57
  JSON.stringify(this.dehydrate(entity)),
56
58
  entity.getId().getValue()
57
59
  );
@@ -62,14 +64,14 @@ var SqliteRepositoryForTest = class {
62
64
  }
63
65
  }
64
66
  async count() {
65
- await this.ensureTableExists();
66
- const result = await this.db.get(
67
+ this.ensureTableExists();
68
+ const result = this.db.prepare(
67
69
  `SELECT COUNT(*) AS count FROM ${this.namespace}`
68
- );
70
+ ).get();
69
71
  return result.count;
70
72
  }
71
- async ensureTableExists() {
72
- await this.db.run(`
73
+ ensureTableExists() {
74
+ this.db.exec(`
73
75
  CREATE TABLE IF NOT EXISTS ${this.namespace} (
74
76
  id TEXT NOT NULL PRIMARY KEY UNIQUE,
75
77
  data TEXT NOT NULL
@@ -77,15 +79,8 @@ var SqliteRepositoryForTest = class {
77
79
  `);
78
80
  }
79
81
  };
80
-
81
- // src/test/utils.ts
82
- async function getSqliteConnection(filename = ":memory:") {
83
- const sqlite = await import('sqlite');
84
- const sqlite3 = await import('sqlite3');
85
- return await sqlite.open({
86
- filename,
87
- driver: sqlite3.default.Database
88
- });
82
+ function getSqliteConnection(filename = ":memory:") {
83
+ return new Database(filename);
89
84
  }
90
85
 
91
86
  export { SqliteRepositoryForTest, getSqliteConnection };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/test/sqlite-repository-for-test.ts","../../src/test/utils.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Database } from \"sqlite\";\n\nimport {\n DuplicateObjectError,\n Identifiable,\n IdOf,\n ObjectNotFoundError,\n Repository,\n} from \"@hexaijs/core\";\n\nexport class SqliteRepositoryForTest<\n E extends Identifiable<any>,\n M,\n> implements Repository<E> {\n protected namespace: string;\n protected hydrate: (memento: M) => E;\n protected dehydrate: (entity: E) => M;\n\n constructor(\n protected db: Database,\n {\n namespace,\n hydrate,\n dehydrate,\n }: {\n namespace: string;\n hydrate: (memento: M) => E;\n dehydrate: (entity: E) => M;\n }\n ) {\n this.namespace = namespace;\n this.hydrate = hydrate;\n this.dehydrate = dehydrate;\n }\n\n async get(id: IdOf<E>): Promise<E> {\n await this.ensureTableExists();\n\n const row = await this.db.get(\n `SELECT * FROM ${this.namespace} WHERE id = ?`,\n id.getValue()\n );\n if (!row) {\n throw new ObjectNotFoundError(\n `entity with id '${id.getValue()}' not found`\n );\n }\n\n return this.hydrate(JSON.parse(row.data));\n }\n\n async add(entity: E): Promise<void> {\n await this.ensureTableExists();\n\n try {\n await this.db.run(\n `INSERT INTO ${this.namespace} (id, data)\n VALUES (?, ?)`,\n entity.getId().getValue(),\n JSON.stringify(this.dehydrate(entity))\n );\n } catch (e) {\n if ((e as Error).message.includes(\"UNIQUE constraint failed\")) {\n throw new DuplicateObjectError(\n `entity with id '${entity\n .getId()\n .getValue()}' already exists`\n );\n }\n\n throw e;\n }\n }\n\n async update(entity: E): Promise<void> {\n await this.ensureTableExists();\n\n const result = await this.db.run(\n `UPDATE ${this.namespace}\n SET data = ?\n WHERE id = ?`,\n JSON.stringify(this.dehydrate(entity)),\n entity.getId().getValue()\n );\n\n if (result.changes === 0) {\n throw new ObjectNotFoundError(\n `entity with id '${entity.getId().getValue()}' not found`\n );\n }\n }\n\n async count(): Promise<number> {\n await this.ensureTableExists();\n\n const result = await this.db.get(\n `SELECT COUNT(*) AS count FROM ${this.namespace}`\n );\n\n return result.count;\n }\n\n protected async ensureTableExists(): Promise<void> {\n await this.db.run(`\n CREATE TABLE IF NOT EXISTS ${this.namespace} (\n id TEXT NOT NULL PRIMARY KEY UNIQUE,\n data TEXT NOT NULL\n )\n `);\n }\n}\n","import type { Database } from \"sqlite\";\n\nexport async function getSqliteConnection(\n filename = \":memory:\"\n): Promise<Database> {\n const sqlite = await import(\"sqlite\");\n const sqlite3 = await import(\"sqlite3\");\n return await sqlite.open({\n filename,\n driver: sqlite3.default.Database,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/test/sqlite-repository-for-test.ts","../../src/test/utils.ts"],"names":[],"mappings":";;;;AAUO,IAAM,0BAAN,MAGoB;AAAA,EAKvB,YACc,EAAA,EACV;AAAA,IACI,SAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,GACJ,EAKF;AAVY,IAAA,IAAA,CAAA,EAAA,GAAA,EAAA;AAWV,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAAA,EACrB;AAAA,EAnBU,SAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EAmBV,MAAM,IAAI,EAAA,EAAyB;AAC/B,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,MAAM,GAAA,GAAM,KAAK,EAAA,CAAG,OAAA;AAAA,MAChB,CAAA,cAAA,EAAiB,KAAK,SAAS,CAAA,aAAA;AAAA,KACnC,CAAE,GAAA,CAAI,EAAA,CAAG,QAAA,EAAU,CAAA;AACnB,IAAA,IAAI,CAAC,GAAA,EAAK;AACN,MAAA,MAAM,IAAI,mBAAA;AAAA,QACN,CAAA,gBAAA,EAAmB,EAAA,CAAG,QAAA,EAAU,CAAA,WAAA;AAAA,OACpC;AAAA,IACJ;AAEA,IAAA,OAAO,KAAK,OAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,IAAI,CAAC,CAAA;AAAA,EAC5C;AAAA,EAEA,MAAM,IAAI,MAAA,EAA0B;AAChC,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,IAAI;AACA,MAAA,IAAA,CAAK,EAAA,CAAG,OAAA;AAAA,QACJ,CAAA,YAAA,EAAe,KAAK,SAAS,CAAA;AAAA,8BAAA;AAAA,OAEjC,CAAE,GAAA;AAAA,QACE,MAAA,CAAO,KAAA,EAAM,CAAE,QAAA,EAAS;AAAA,QACxB,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,SAAA,CAAU,MAAM,CAAC;AAAA,OACzC;AAAA,IACJ,SAAS,CAAA,EAAG;AACR,MAAA,IAAK,CAAA,CAAY,OAAA,CAAQ,QAAA,CAAS,0BAA0B,CAAA,EAAG;AAC3D,QAAA,MAAM,IAAI,oBAAA;AAAA,UACN,CAAA,gBAAA,EAAmB,MAAA,CACd,KAAA,EAAM,CACN,UAAU,CAAA,gBAAA;AAAA,SACnB;AAAA,MACJ;AAEA,MAAA,MAAM,CAAA;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,MAAM,OAAO,MAAA,EAA0B;AACnC,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,MAAM,MAAA,GAAS,KAAK,EAAA,CAAG,OAAA;AAAA,MACnB,CAAA,OAAA,EAAU,KAAK,SAAS;AAAA;AAAA,6BAAA;AAAA,KAG5B,CAAE,GAAA;AAAA,MACE,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,SAAA,CAAU,MAAM,CAAC,CAAA;AAAA,MACrC,MAAA,CAAO,KAAA,EAAM,CAAE,QAAA;AAAS,KAC5B;AAEA,IAAA,IAAI,MAAA,CAAO,YAAY,CAAA,EAAG;AACtB,MAAA,MAAM,IAAI,mBAAA;AAAA,QACN,CAAA,gBAAA,EAAmB,MAAA,CAAO,KAAA,EAAM,CAAE,UAAU,CAAA,WAAA;AAAA,OAChD;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,MAAM,KAAA,GAAyB;AAC3B,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,MAAM,MAAA,GAAS,KAAK,EAAA,CAAG,OAAA;AAAA,MACnB,CAAA,8BAAA,EAAiC,KAAK,SAAS,CAAA;AAAA,MACjD,GAAA,EAAI;AAEN,IAAA,OAAO,MAAA,CAAO,KAAA;AAAA,EAClB;AAAA,EAEU,iBAAA,GAA0B;AAChC,IAAA,IAAA,CAAK,GAAG,IAAA,CAAK;AAAA,uCAAA,EACoB,KAAK,SAAS,CAAA;AAAA;AAAA;AAAA;AAAA,QAAA,CAI9C,CAAA;AAAA,EACL;AACJ;AC5GO,SAAS,mBAAA,CACZ,WAAW,UAAA,EACK;AAChB,EAAA,OAAO,IAAI,SAAS,QAAQ,CAAA;AAChC","file":"index.js","sourcesContent":["import type { Database } from \"better-sqlite3\";\n\nimport {\n DuplicateObjectError,\n Identifiable,\n IdOf,\n ObjectNotFoundError,\n Repository,\n} from \"@hexaijs/core\";\n\nexport class SqliteRepositoryForTest<\n E extends Identifiable<any>,\n M,\n> implements Repository<E> {\n protected namespace: string;\n protected hydrate: (memento: M) => E;\n protected dehydrate: (entity: E) => M;\n\n constructor(\n protected db: Database,\n {\n namespace,\n hydrate,\n dehydrate,\n }: {\n namespace: string;\n hydrate: (memento: M) => E;\n dehydrate: (entity: E) => M;\n }\n ) {\n this.namespace = namespace;\n this.hydrate = hydrate;\n this.dehydrate = dehydrate;\n }\n\n async get(id: IdOf<E>): Promise<E> {\n this.ensureTableExists();\n\n const row = this.db.prepare(\n `SELECT * FROM ${this.namespace} WHERE id = ?`\n ).get(id.getValue()) as { data: string } | undefined;\n if (!row) {\n throw new ObjectNotFoundError(\n `entity with id '${id.getValue()}' not found`\n );\n }\n\n return this.hydrate(JSON.parse(row.data));\n }\n\n async add(entity: E): Promise<void> {\n this.ensureTableExists();\n\n try {\n this.db.prepare(\n `INSERT INTO ${this.namespace} (id, data)\n VALUES (?, ?)`\n ).run(\n entity.getId().getValue(),\n JSON.stringify(this.dehydrate(entity))\n );\n } catch (e) {\n if ((e as Error).message.includes(\"UNIQUE constraint failed\")) {\n throw new DuplicateObjectError(\n `entity with id '${entity\n .getId()\n .getValue()}' already exists`\n );\n }\n\n throw e;\n }\n }\n\n async update(entity: E): Promise<void> {\n this.ensureTableExists();\n\n const result = this.db.prepare(\n `UPDATE ${this.namespace}\n SET data = ?\n WHERE id = ?`\n ).run(\n JSON.stringify(this.dehydrate(entity)),\n entity.getId().getValue()\n );\n\n if (result.changes === 0) {\n throw new ObjectNotFoundError(\n `entity with id '${entity.getId().getValue()}' not found`\n );\n }\n }\n\n async count(): Promise<number> {\n this.ensureTableExists();\n\n const result = this.db.prepare(\n `SELECT COUNT(*) AS count FROM ${this.namespace}`\n ).get() as { count: number };\n\n return result.count;\n }\n\n protected ensureTableExists(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${this.namespace} (\n id TEXT NOT NULL PRIMARY KEY UNIQUE,\n data TEXT NOT NULL\n )\n `);\n }\n}\n","import Database from \"better-sqlite3\";\nimport type { Database as DatabaseInstance } from \"better-sqlite3\";\n\nexport function getSqliteConnection(\n filename = \":memory:\"\n): DatabaseInstance {\n return new Database(filename);\n}\n"]}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.3.0",
6
+ "version": "0.5.0",
7
7
  "type": "module",
8
8
  "description": "SQLite support for hexai",
9
9
  "license": "MIT",
@@ -50,14 +50,13 @@
50
50
  },
51
51
  "dependencies": {},
52
52
  "peerDependencies": {
53
- "@hexaijs/core": "^0.7.0",
54
- "sqlite": "^5.1.1",
55
- "sqlite3": "^5.1.7"
53
+ "@hexaijs/core": "^0.9.0",
54
+ "better-sqlite3": "^12.5.0"
56
55
  },
57
56
  "devDependencies": {
58
57
  "@hexaijs/core": "workspace:^",
59
58
  "@hexaijs/tooling": "workspace:*",
60
- "sqlite": "^5.1.1",
61
- "sqlite3": "^5.1.7"
59
+ "@types/better-sqlite3": "^7.6.13",
60
+ "better-sqlite3": "^12.5.0"
62
61
  }
63
62
  }