@hexaijs/sqlite 0.4.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 +26 -30
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/test/index.d.ts +3 -3
- package/dist/test/index.js +20 -25
- package/dist/test/index.js.map +1 -1
- package/package.json +59 -60
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
|
|
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
|
|
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 =
|
|
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
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,7 +95,7 @@ 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
|
-
|
|
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.
|
|
@@ -110,20 +106,20 @@ Register callbacks that execute at specific points in the transaction lifecycle:
|
|
|
110
106
|
|
|
111
107
|
```typescript
|
|
112
108
|
await unitOfWork.scope(async () => {
|
|
113
|
-
unitOfWork.beforeCommit(
|
|
109
|
+
unitOfWork.beforeCommit(() => {
|
|
114
110
|
// Validate before committing
|
|
115
111
|
});
|
|
116
112
|
|
|
117
|
-
unitOfWork.afterCommit(
|
|
113
|
+
unitOfWork.afterCommit(() => {
|
|
118
114
|
// Notify after successful commit
|
|
119
115
|
});
|
|
120
116
|
|
|
121
|
-
unitOfWork.afterRollback(
|
|
117
|
+
unitOfWork.afterRollback(() => {
|
|
122
118
|
// Clean up on failure
|
|
123
119
|
});
|
|
124
120
|
|
|
125
121
|
const db = unitOfWork.getClient();
|
|
126
|
-
|
|
122
|
+
db.prepare("INSERT INTO orders (id, status) VALUES (?, ?)").run(orderId, "pending");
|
|
127
123
|
});
|
|
128
124
|
```
|
|
129
125
|
|
|
@@ -144,11 +140,11 @@ Nested `scope()` calls participate in the same transaction:
|
|
|
144
140
|
```typescript
|
|
145
141
|
await unitOfWork.scope(async () => {
|
|
146
142
|
const db = unitOfWork.getClient();
|
|
147
|
-
|
|
143
|
+
db.prepare("INSERT INTO orders (id) VALUES (?)").run("order-1");
|
|
148
144
|
|
|
149
145
|
await unitOfWork.scope(async () => {
|
|
150
146
|
const db = unitOfWork.getClient();
|
|
151
|
-
|
|
147
|
+
db.prepare("INSERT INTO order_items (order_id) VALUES (?)").run("order-1");
|
|
152
148
|
});
|
|
153
149
|
// Both inserts are in the same transaction
|
|
154
150
|
});
|
|
@@ -161,11 +157,11 @@ If any nested call throws, the entire transaction rolls back:
|
|
|
161
157
|
try {
|
|
162
158
|
await unitOfWork.scope(async () => {
|
|
163
159
|
const db = unitOfWork.getClient();
|
|
164
|
-
|
|
160
|
+
db.prepare("INSERT INTO orders (id) VALUES (?)").run("order-1");
|
|
165
161
|
|
|
166
162
|
await unitOfWork.scope(async () => {
|
|
167
163
|
const db = unitOfWork.getClient();
|
|
168
|
-
|
|
164
|
+
db.prepare("INSERT INTO order_items (order_id) VALUES (?)").run("order-1");
|
|
169
165
|
throw new Error("Nested failure");
|
|
170
166
|
});
|
|
171
167
|
});
|
|
@@ -181,7 +177,7 @@ try {
|
|
|
181
177
|
Use the test utilities for fast, isolated integration tests:
|
|
182
178
|
|
|
183
179
|
```typescript
|
|
184
|
-
import type { Database } from "
|
|
180
|
+
import type { Database } from "better-sqlite3";
|
|
185
181
|
import { SqliteUnitOfWork } from "@hexaijs/sqlite";
|
|
186
182
|
import { getSqliteConnection } from "@hexaijs/sqlite/test";
|
|
187
183
|
|
|
@@ -189,12 +185,12 @@ describe("OrderRepository", () => {
|
|
|
189
185
|
let db: Database;
|
|
190
186
|
let unitOfWork: SqliteUnitOfWork;
|
|
191
187
|
|
|
192
|
-
beforeEach(
|
|
188
|
+
beforeEach(() => {
|
|
193
189
|
// Create fresh in-memory database
|
|
194
|
-
db =
|
|
190
|
+
db = getSqliteConnection();
|
|
195
191
|
|
|
196
192
|
// Create schema
|
|
197
|
-
|
|
193
|
+
db.exec(`
|
|
198
194
|
CREATE TABLE orders (
|
|
199
195
|
id TEXT PRIMARY KEY,
|
|
200
196
|
status TEXT NOT NULL
|
|
@@ -204,17 +200,17 @@ describe("OrderRepository", () => {
|
|
|
204
200
|
unitOfWork = new SqliteUnitOfWork(db);
|
|
205
201
|
});
|
|
206
202
|
|
|
207
|
-
afterEach(
|
|
208
|
-
|
|
203
|
+
afterEach(() => {
|
|
204
|
+
db.close();
|
|
209
205
|
});
|
|
210
206
|
|
|
211
207
|
it("should persist orders", async () => {
|
|
212
208
|
await unitOfWork.scope(async () => {
|
|
213
209
|
const db = unitOfWork.getClient();
|
|
214
|
-
|
|
210
|
+
db.prepare("INSERT INTO orders (id, status) VALUES (?, ?)").run("order-1", "pending");
|
|
215
211
|
});
|
|
216
212
|
|
|
217
|
-
const result =
|
|
213
|
+
const result = db.prepare("SELECT * FROM orders WHERE id = ?").get("order-1") as any;
|
|
218
214
|
expect(result.status).toBe("pending");
|
|
219
215
|
});
|
|
220
216
|
});
|
|
@@ -251,7 +247,7 @@ interface OrderMemento {
|
|
|
251
247
|
}
|
|
252
248
|
|
|
253
249
|
// Create repository
|
|
254
|
-
const db =
|
|
250
|
+
const db = getSqliteConnection();
|
|
255
251
|
const orderRepository = new SqliteRepositoryForTest<Order, OrderMemento>(db, {
|
|
256
252
|
namespace: "orders",
|
|
257
253
|
hydrate: (m) => new Order(new OrderId(m.id), m.status),
|
|
@@ -275,7 +271,7 @@ For scenarios requiring persistence across test runs or debugging:
|
|
|
275
271
|
import { getSqliteConnection } from "@hexaijs/sqlite/test";
|
|
276
272
|
|
|
277
273
|
// File-based database instead of in-memory
|
|
278
|
-
const db =
|
|
274
|
+
const db = getSqliteConnection("./test-database.sqlite");
|
|
279
275
|
```
|
|
280
276
|
|
|
281
277
|
## API Highlights
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -38,7 +38,7 @@ var SqliteUnitOfWork = class _SqliteUnitOfWork {
|
|
|
38
38
|
async wrap(fn) {
|
|
39
39
|
const current = _SqliteUnitOfWork.transactions.get(this.db);
|
|
40
40
|
if (++current.level === 1) {
|
|
41
|
-
|
|
41
|
+
this.db.exec("BEGIN TRANSACTION");
|
|
42
42
|
}
|
|
43
43
|
let abortError;
|
|
44
44
|
try {
|
|
@@ -58,17 +58,17 @@ var SqliteUnitOfWork = class _SqliteUnitOfWork {
|
|
|
58
58
|
if (wasAborted) {
|
|
59
59
|
await hooks.executeRollback(
|
|
60
60
|
async () => {
|
|
61
|
-
|
|
61
|
+
this.db.exec("ROLLBACK");
|
|
62
62
|
},
|
|
63
63
|
abortError
|
|
64
64
|
);
|
|
65
65
|
} else {
|
|
66
66
|
await hooks.executeCommit(
|
|
67
67
|
async () => {
|
|
68
|
-
|
|
68
|
+
this.db.exec("COMMIT");
|
|
69
69
|
},
|
|
70
70
|
async () => {
|
|
71
|
-
|
|
71
|
+
this.db.exec("ROLLBACK");
|
|
72
72
|
}
|
|
73
73
|
);
|
|
74
74
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sqlite-unit-of-work.ts"],"names":[],"mappings":";;;AAKO,IAAM,gBAAA,GAAN,MAAM,iBAAA,CAAiD;AAAA,EAU1D,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,KAAA;AAAA,QACT,KAAA,EAAO,IAAI,gBAAA;AAAiB,OAC/B,CAAA;AAAA,IACL;AAAA,EACJ;AAAA,EAjBA,OAAe,YAAA,mBAAe,IAAI,OAAA,EAOhC;AAAA,EAYF,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,aAAa,IAAA,EAA6B;AACtC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,CAAiB,cAAc,CAAA;AACpD,IAAA,OAAA,CAAQ,KAAA,CAAM,gBAAgB,IAAI,CAAA;AAAA,EACtC;AAAA,EAEA,YAAY,IAAA,EAA6B;AACrC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,CAAiB,aAAa,CAAA;AACnD,IAAA,OAAA,CAAQ,KAAA,CAAM,eAAe,IAAI,CAAA;AAAA,EACrC;AAAA,EAEA,cAAc,IAAA,EAA6B;AACvC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,CAAiB,eAAe,CAAA;AACrD,IAAA,OAAA,CAAQ,KAAA,CAAM,iBAAiB,IAAI,CAAA;AAAA,EACvC;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,
|
|
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"]}
|
package/dist/test/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Database } from '
|
|
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():
|
|
18
|
+
protected ensureTableExists(): void;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
declare function getSqliteConnection(filename?: string):
|
|
21
|
+
declare function getSqliteConnection(filename?: string): Database;
|
|
22
22
|
|
|
23
23
|
export { SqliteRepositoryForTest, getSqliteConnection };
|
package/dist/test/index.js
CHANGED
|
@@ -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
|
-
|
|
20
|
-
const row =
|
|
21
|
-
`SELECT * FROM ${this.namespace} WHERE id =
|
|
22
|
-
|
|
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
|
-
|
|
32
|
+
this.ensureTableExists();
|
|
33
33
|
try {
|
|
34
|
-
|
|
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
|
-
|
|
51
|
-
const result =
|
|
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
|
-
|
|
66
|
-
const result =
|
|
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
|
-
|
|
72
|
-
|
|
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
|
-
|
|
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 };
|
package/dist/test/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/test/sqlite-repository-for-test.ts","../../src/test/utils.ts"],"names":[],"mappings":"
|
|
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 \"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
|
@@ -1,63 +1,62 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
},
|
|
6
|
-
"version": "0.4.0",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"description": "SQLite support for hexai",
|
|
9
|
-
"license": "MIT",
|
|
10
|
-
"author": "Sangwoo Hyun <wkdny.hyun@gmail.com>",
|
|
11
|
-
"contributors": [
|
|
12
|
-
"Seungcheol Baek <victoryiron.baek@gmail.com>",
|
|
13
|
-
"Donghyun Lee <edonghyun@naver.com>"
|
|
14
|
-
],
|
|
15
|
-
"repository": {
|
|
16
|
-
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/workingdanny911/hexai.git",
|
|
18
|
-
"directory": "packages/sqlite"
|
|
19
|
-
},
|
|
20
|
-
"homepage": "https://github.com/workingdanny911/hexai#readme",
|
|
21
|
-
"bugs": {
|
|
22
|
-
"url": "https://github.com/workingdanny911/hexai/issues"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"hexai",
|
|
26
|
-
"hexagonal",
|
|
27
|
-
"clean-architecture",
|
|
28
|
-
"sqlite",
|
|
29
|
-
"database",
|
|
30
|
-
"typescript"
|
|
31
|
-
],
|
|
32
|
-
"files": [
|
|
33
|
-
"dist",
|
|
34
|
-
"LICENSE"
|
|
35
|
-
],
|
|
36
|
-
"exports": {
|
|
37
|
-
".": {
|
|
38
|
-
"types": "./dist/index.d.ts",
|
|
39
|
-
"import": "./dist/index.js"
|
|
2
|
+
"name": "@hexaijs/sqlite",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
40
5
|
},
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
6
|
+
"version": "0.5.0",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"description": "SQLite support for hexai",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"author": "Sangwoo Hyun <wkdny.hyun@gmail.com>",
|
|
11
|
+
"contributors": [
|
|
12
|
+
"Seungcheol Baek <victoryiron.baek@gmail.com>",
|
|
13
|
+
"Donghyun Lee <edonghyun@naver.com>"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/workingdanny911/hexai.git",
|
|
18
|
+
"directory": "packages/sqlite"
|
|
44
19
|
},
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
20
|
+
"homepage": "https://github.com/workingdanny911/hexai#readme",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/workingdanny911/hexai/issues"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"hexai",
|
|
26
|
+
"hexagonal",
|
|
27
|
+
"clean-architecture",
|
|
28
|
+
"sqlite",
|
|
29
|
+
"database",
|
|
30
|
+
"typescript"
|
|
31
|
+
],
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"import": "./dist/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./test": {
|
|
42
|
+
"types": "./dist/test/index.d.ts",
|
|
43
|
+
"import": "./dist/test/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./package.json": "./package.json"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"build": "tsup"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@hexaijs/core": "^0.9.0",
|
|
54
|
+
"better-sqlite3": "^12.5.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@hexaijs/core": "workspace:^",
|
|
58
|
+
"@hexaijs/tooling": "workspace:*",
|
|
59
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
60
|
+
"better-sqlite3": "^12.5.0"
|
|
61
|
+
}
|
|
62
|
+
}
|