@cibule/db-sqlite 0.1.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.
- package/README.md +132 -0
- package/dist/index.cjs +132 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +7 -0
- package/dist/lib/create-sqlite-db.d.ts +3 -0
- package/dist/lib/create-sqlite-db.d.ts.map +1 -0
- package/dist/lib/provider.d.ts +3 -0
- package/dist/lib/provider.d.ts.map +1 -0
- package/dist/lib/sqlite-unit-of-work.d.ts +10 -0
- package/dist/lib/sqlite-unit-of-work.d.ts.map +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# @cibule/db-sqlite
|
|
2
|
+
|
|
3
|
+
SQLite driver for `@cibule/db`, built on better-sqlite3 and Kysely.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @cibule/db-sqlite
|
|
9
|
+
# or
|
|
10
|
+
bun add @cibule/db-sqlite
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @cibule/db-sqlite
|
|
13
|
+
# or
|
|
14
|
+
yarn add @cibule/db-sqlite
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Dependencies `@cibule/db`, `@cibule/di`, `kysely`, and `better-sqlite3` are installed automatically.
|
|
18
|
+
|
|
19
|
+
> **Node.js only** — `better-sqlite3` is a native addon and requires a Node.js runtime. For Cloudflare Workers, use `@cibule/db-d1` instead.
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### With DI (recommended)
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { Injector } from '@cibule/di';
|
|
27
|
+
import { DB_ACCESSOR, UNIT_OF_WORK_FACTORY } from '@cibule/db';
|
|
28
|
+
import { provideSqliteDb } from '@cibule/db-sqlite';
|
|
29
|
+
|
|
30
|
+
interface MySchema {
|
|
31
|
+
users: { id: number; name: string; email: string };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const injector = Injector.create({
|
|
35
|
+
providers: provideSqliteDb('./data.db'),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await injector.runInContext(async () => {
|
|
39
|
+
const dbAccessor = injector.get(DB_ACCESSOR);
|
|
40
|
+
const db = dbAccessor();
|
|
41
|
+
|
|
42
|
+
const users = await db.selectFrom('users').selectAll().execute();
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Without DI
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { createSqliteDb } from '@cibule/db-sqlite';
|
|
50
|
+
|
|
51
|
+
interface MySchema {
|
|
52
|
+
users: { id: number; name: string; email: string };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const db = createSqliteDb<MySchema>('./data.db');
|
|
56
|
+
|
|
57
|
+
const users = await db.selectFrom('users').selectAll().execute();
|
|
58
|
+
|
|
59
|
+
await db.destroy();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## API Reference
|
|
63
|
+
|
|
64
|
+
### createSqliteDb\<Schema\>(filename)
|
|
65
|
+
|
|
66
|
+
Creates a `Db<Schema>` instance backed by a SQLite file via better-sqlite3. Pass `':memory:'` for an in-memory database.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { createSqliteDb } from '@cibule/db-sqlite';
|
|
70
|
+
|
|
71
|
+
const db = createSqliteDb<MySchema>('./data.db');
|
|
72
|
+
const memoryDb = createSqliteDb<MySchema>(':memory:');
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### SqliteUnitOfWork
|
|
76
|
+
|
|
77
|
+
Implements the `UnitOfWork` interface from `@cibule/db`. Executes batched queries atomically inside a Kysely transaction — all queries succeed or all are rolled back.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { createSqliteDb, SqliteUnitOfWork } from '@cibule/db-sqlite';
|
|
81
|
+
|
|
82
|
+
const db = createSqliteDb<MySchema>(':memory:');
|
|
83
|
+
const uow = new SqliteUnitOfWork(db);
|
|
84
|
+
|
|
85
|
+
uow.add(db.insertInto('users').values({ id: 1, name: 'Alice', email: 'a@b.com' }).compile());
|
|
86
|
+
uow.add(db.insertInto('users').values({ id: 2, name: 'Bob', email: 'b@b.com' }).compile());
|
|
87
|
+
|
|
88
|
+
await uow.execute(); // atomic — both inserts succeed or both roll back
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Key behaviors:
|
|
92
|
+
|
|
93
|
+
- Empty batch: `execute()` returns immediately without opening a transaction
|
|
94
|
+
- Queries are cleared before execution begins, preventing accidental double-execution
|
|
95
|
+
- On failure: the transaction is rolled back (no partial writes); queries are already cleared and cannot be retried — callers must re-add queries if retry is needed
|
|
96
|
+
|
|
97
|
+
### provideSqliteDb(filename)
|
|
98
|
+
|
|
99
|
+
Returns a `Provider[]` that registers both `DB_ACCESSOR` and `UNIT_OF_WORK_FACTORY` with the DI container.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { Injector } from '@cibule/di';
|
|
103
|
+
import { DB_ACCESSOR, UNIT_OF_WORK_FACTORY } from '@cibule/db';
|
|
104
|
+
import { provideSqliteDb } from '@cibule/db-sqlite';
|
|
105
|
+
|
|
106
|
+
const injector = Injector.create({
|
|
107
|
+
providers: provideSqliteDb('./data.db'),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
injector.runInContext(() => {
|
|
111
|
+
const dbAccessor = injector.get(DB_ACCESSOR);
|
|
112
|
+
const db = dbAccessor(); // Kysely<any> instance
|
|
113
|
+
|
|
114
|
+
const uowFactory = injector.get(UNIT_OF_WORK_FACTORY);
|
|
115
|
+
const uow = uowFactory(); // fresh SqliteUnitOfWork per call
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The `DB_ACCESSOR` returns the same Kysely instance on every call (singleton). The `UNIT_OF_WORK_FACTORY` returns a fresh `SqliteUnitOfWork` on every call (double-factory pattern).
|
|
120
|
+
|
|
121
|
+
## Related Packages
|
|
122
|
+
|
|
123
|
+
| Package | Description | Heavy dependency |
|
|
124
|
+
| -------------------- | ---------------------------- | -------------------- |
|
|
125
|
+
| `@cibule/db` | Core types + mock driver | None (built-in) |
|
|
126
|
+
| `@cibule/db-sqlite` | SQLite driver (this package) | `better-sqlite3` |
|
|
127
|
+
| `@cibule/db-d1` | Cloudflare D1 driver | `kysely-d1` |
|
|
128
|
+
| `@cibule/db-migrate` | Migration orchestrator | `prisma`, `wrangler` |
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
SqliteUnitOfWork: () => SqliteUnitOfWork,
|
|
34
|
+
createSqliteDb: () => createSqliteDb,
|
|
35
|
+
provideSqliteDb: () => provideSqliteDb
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
|
+
|
|
39
|
+
// src/lib/create-sqlite-db.ts
|
|
40
|
+
var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
|
|
41
|
+
var import_kysely = require("kysely");
|
|
42
|
+
function createSqliteDb(filename) {
|
|
43
|
+
return new import_kysely.Kysely({
|
|
44
|
+
dialect: new import_kysely.SqliteDialect({
|
|
45
|
+
database: new import_better_sqlite3.default(filename)
|
|
46
|
+
})
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ../di/src/lib/context.ts
|
|
51
|
+
var currentInjector = null;
|
|
52
|
+
function getCurrentInjector() {
|
|
53
|
+
return currentInjector;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ../di/src/lib/inject.ts
|
|
57
|
+
function inject(token, options) {
|
|
58
|
+
const injector = getCurrentInjector();
|
|
59
|
+
if (!injector) {
|
|
60
|
+
throw new Error("inject() must be called within an injection context (runInContext)");
|
|
61
|
+
}
|
|
62
|
+
return options ? injector.get(token, options) : injector.get(token);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ../di/src/lib/injection-token.ts
|
|
66
|
+
var InjectionToken = class {
|
|
67
|
+
constructor(description) {
|
|
68
|
+
this.description = description;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// ../db/src/lib/db-accessor.ts
|
|
73
|
+
var DB_ACCESSOR = new InjectionToken("DB_ACCESSOR");
|
|
74
|
+
|
|
75
|
+
// ../db/src/lib/provider.ts
|
|
76
|
+
function provideDbAccessor(factory) {
|
|
77
|
+
return { provide: DB_ACCESSOR, useFactory: factory };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ../db/src/lib/unit-of-work.ts
|
|
81
|
+
var UNIT_OF_WORK_FACTORY = new InjectionToken("UNIT_OF_WORK_FACTORY");
|
|
82
|
+
|
|
83
|
+
// src/lib/sqlite-unit-of-work.ts
|
|
84
|
+
var SqliteUnitOfWork = class {
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
86
|
+
constructor(db) {
|
|
87
|
+
this.db = db;
|
|
88
|
+
}
|
|
89
|
+
queries = [];
|
|
90
|
+
add(query) {
|
|
91
|
+
this.queries.push(query);
|
|
92
|
+
}
|
|
93
|
+
async execute() {
|
|
94
|
+
if (this.queries.length === 0) return;
|
|
95
|
+
const batch = [...this.queries];
|
|
96
|
+
this.queries = [];
|
|
97
|
+
try {
|
|
98
|
+
await this.db.transaction().execute(async (trx) => {
|
|
99
|
+
for (const query of batch) {
|
|
100
|
+
await trx.executeQuery(query);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
this.queries = [...batch, ...this.queries];
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// src/lib/provider.ts
|
|
111
|
+
function provideSqliteDb(filename) {
|
|
112
|
+
return [
|
|
113
|
+
provideDbAccessor(() => {
|
|
114
|
+
const db = createSqliteDb(filename);
|
|
115
|
+
return () => db;
|
|
116
|
+
}),
|
|
117
|
+
{
|
|
118
|
+
provide: UNIT_OF_WORK_FACTORY,
|
|
119
|
+
useFactory: () => {
|
|
120
|
+
const dbAccessor = inject(DB_ACCESSOR);
|
|
121
|
+
return () => new SqliteUnitOfWork(dbAccessor());
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
];
|
|
125
|
+
}
|
|
126
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
127
|
+
0 && (module.exports = {
|
|
128
|
+
SqliteUnitOfWork,
|
|
129
|
+
createSqliteDb,
|
|
130
|
+
provideSqliteDb
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts", "../src/lib/create-sqlite-db.ts", "../../di/src/lib/context.ts", "../../di/src/lib/inject.ts", "../../di/src/lib/injection-token.ts", "../../db/src/lib/db-accessor.ts", "../../db/src/lib/provider.ts", "../../db/src/lib/unit-of-work.ts", "../src/lib/sqlite-unit-of-work.ts", "../src/lib/provider.ts"],
|
|
4
|
+
"sourcesContent": ["export { createSqliteDb } from './lib/create-sqlite-db';\nexport { provideSqliteDb } from './lib/provider';\nexport { SqliteUnitOfWork } from './lib/sqlite-unit-of-work';\n", "import type { Db } from '@cibule/db';\nimport Database from 'better-sqlite3';\nimport { Kysely, SqliteDialect } from 'kysely';\n\nexport function createSqliteDb<Schema>(filename: string): Db<Schema> {\n return new Kysely<Schema>({\n dialect: new SqliteDialect({\n database: new Database(filename),\n }),\n });\n}\n", "import type { Injector } from './injector';\n\nlet currentInjector: Injector | null = null;\n\nexport function getCurrentInjector(): Injector | null {\n return currentInjector;\n}\n\nexport function setCurrentInjector(injector: Injector | null): Injector | null {\n const previous = currentInjector;\n currentInjector = injector;\n return previous;\n}\n", "import { getCurrentInjector } from './context';\nimport type { InjectOptions } from './provider';\nimport type { Token } from './token';\n\nexport function inject<T>(token: Token<T>): T;\nexport function inject<T>(token: Token<T>, options: InjectOptions): T | null;\nexport function inject<T>(token: Token<T>, options?: InjectOptions): T | null {\n const injector = getCurrentInjector();\n\n if (!injector) {\n throw new Error('inject() must be called within an injection context (runInContext)');\n }\n\n return options ? injector.get(token, options) : injector.get(token);\n}\n", "export class InjectionToken<T> {\n declare readonly _brand: T;\n constructor(public readonly description: string) {}\n}\n", "import { InjectionToken } from '@cibule/di';\n\nimport type { Db } from './db';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type DbAccessor<Schema = any> = () => Db<Schema>;\n\nexport const DB_ACCESSOR = new InjectionToken<DbAccessor>('DB_ACCESSOR');\n", "import type { Provider } from '@cibule/di';\n\nimport type { DbAccessor } from './db-accessor';\nimport { DB_ACCESSOR } from './db-accessor';\n\nexport function provideDbAccessor<S>(factory: () => DbAccessor<S>): Provider {\n return { provide: DB_ACCESSOR, useFactory: factory };\n}\n", "import { InjectionToken } from '@cibule/di';\nimport type { CompiledQuery } from 'kysely';\n\nexport interface UnitOfWork {\n add<T>(query: CompiledQuery<T>): void;\n execute(): Promise<void>;\n}\n\nexport type UnitOfWorkFactory = () => UnitOfWork;\n\nexport const UNIT_OF_WORK_FACTORY = new InjectionToken<UnitOfWorkFactory>('UNIT_OF_WORK_FACTORY');\n", "import type { UnitOfWork } from '@cibule/db';\nimport type { CompiledQuery, Kysely } from 'kysely';\n\nexport class SqliteUnitOfWork implements UnitOfWork {\n private queries: CompiledQuery[] = [];\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public constructor(private readonly db: Kysely<any>) {}\n\n public add<T>(query: CompiledQuery<T>): void {\n this.queries.push(query);\n }\n\n public async execute(): Promise<void> {\n if (this.queries.length === 0) return;\n\n const batch = [...this.queries];\n this.queries = [];\n\n try {\n await this.db.transaction().execute(async trx => {\n for (const query of batch) {\n await trx.executeQuery(query);\n }\n });\n } catch (error: unknown) {\n this.queries = [...batch, ...this.queries];\n throw error;\n }\n }\n}\n", "import { DB_ACCESSOR, provideDbAccessor, UNIT_OF_WORK_FACTORY } from '@cibule/db';\nimport type { Provider } from '@cibule/di';\nimport { inject } from '@cibule/di';\n\nimport { createSqliteDb } from './create-sqlite-db';\nimport { SqliteUnitOfWork } from './sqlite-unit-of-work';\n\nexport function provideSqliteDb(filename: string): Provider[] {\n return [\n provideDbAccessor(() => {\n const db = createSqliteDb(filename);\n return () => db;\n }),\n {\n provide: UNIT_OF_WORK_FACTORY,\n useFactory: () => {\n const dbAccessor = inject(DB_ACCESSOR);\n return () => new SqliteUnitOfWork(dbAccessor());\n },\n },\n ];\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,4BAAqB;AACrB,oBAAsC;AAE/B,SAAS,eAAuB,UAA8B;AACnE,SAAO,IAAI,qBAAe;AAAA,IACxB,SAAS,IAAI,4BAAc;AAAA,MACzB,UAAU,IAAI,sBAAAA,QAAS,QAAQ;AAAA,IACjC,CAAC;AAAA,EACH,CAAC;AACH;;;ACRA,IAAI,kBAAmC;AAEhC,SAAS,qBAAsC;AACpD,SAAO;AACT;;;ACAO,SAAS,OAAU,OAAiB,SAAmC;AAC5E,QAAM,WAAW,mBAAmB;AAEpC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,oEAAoE;AAAA,EACtF;AAEA,SAAO,UAAU,SAAS,IAAI,OAAO,OAAO,IAAI,SAAS,IAAI,KAAK;AACpE;;;ACdO,IAAM,iBAAN,MAAwB;AAAA,EAE7B,YAA4B,aAAqB;AAArB;AAAA,EAAsB;AACpD;;;ACIO,IAAM,cAAc,IAAI,eAA2B,aAAa;;;ACFhE,SAAS,kBAAqB,SAAwC;AAC3E,SAAO,EAAE,SAAS,aAAa,YAAY,QAAQ;AACrD;;;ACGO,IAAM,uBAAuB,IAAI,eAAkC,sBAAsB;;;ACPzF,IAAM,mBAAN,MAA6C;AAAA;AAAA,EAI3C,YAA6B,IAAiB;AAAjB;AAAA,EAAkB;AAAA,EAH9C,UAA2B,CAAC;AAAA,EAK7B,IAAO,OAA+B;AAC3C,SAAK,QAAQ,KAAK,KAAK;AAAA,EACzB;AAAA,EAEA,MAAa,UAAyB;AACpC,QAAI,KAAK,QAAQ,WAAW,EAAG;AAE/B,UAAM,QAAQ,CAAC,GAAG,KAAK,OAAO;AAC9B,SAAK,UAAU,CAAC;AAEhB,QAAI;AACF,YAAM,KAAK,GAAG,YAAY,EAAE,QAAQ,OAAM,QAAO;AAC/C,mBAAW,SAAS,OAAO;AACzB,gBAAM,IAAI,aAAa,KAAK;AAAA,QAC9B;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAgB;AACvB,WAAK,UAAU,CAAC,GAAG,OAAO,GAAG,KAAK,OAAO;AACzC,YAAM;AAAA,IACR;AAAA,EACF;AACF;;;ACvBO,SAAS,gBAAgB,UAA8B;AAC5D,SAAO;AAAA,IACL,kBAAkB,MAAM;AACtB,YAAM,KAAK,eAAe,QAAQ;AAClC,aAAO,MAAM;AAAA,IACf,CAAC;AAAA,IACD;AAAA,MACE,SAAS;AAAA,MACT,YAAY,MAAM;AAChB,cAAM,aAAa,OAAO,WAAW;AACrC,eAAO,MAAM,IAAI,iBAAiB,WAAW,CAAC;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": ["Database"]
|
|
7
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// src/lib/create-sqlite-db.ts
|
|
2
|
+
import Database from "better-sqlite3";
|
|
3
|
+
import { Kysely, SqliteDialect } from "kysely";
|
|
4
|
+
function createSqliteDb(filename) {
|
|
5
|
+
return new Kysely({
|
|
6
|
+
dialect: new SqliteDialect({
|
|
7
|
+
database: new Database(filename)
|
|
8
|
+
})
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// ../di/src/lib/context.ts
|
|
13
|
+
var currentInjector = null;
|
|
14
|
+
function getCurrentInjector() {
|
|
15
|
+
return currentInjector;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// ../di/src/lib/inject.ts
|
|
19
|
+
function inject(token, options) {
|
|
20
|
+
const injector = getCurrentInjector();
|
|
21
|
+
if (!injector) {
|
|
22
|
+
throw new Error("inject() must be called within an injection context (runInContext)");
|
|
23
|
+
}
|
|
24
|
+
return options ? injector.get(token, options) : injector.get(token);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ../di/src/lib/injection-token.ts
|
|
28
|
+
var InjectionToken = class {
|
|
29
|
+
constructor(description) {
|
|
30
|
+
this.description = description;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// ../db/src/lib/db-accessor.ts
|
|
35
|
+
var DB_ACCESSOR = new InjectionToken("DB_ACCESSOR");
|
|
36
|
+
|
|
37
|
+
// ../db/src/lib/provider.ts
|
|
38
|
+
function provideDbAccessor(factory) {
|
|
39
|
+
return { provide: DB_ACCESSOR, useFactory: factory };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ../db/src/lib/unit-of-work.ts
|
|
43
|
+
var UNIT_OF_WORK_FACTORY = new InjectionToken("UNIT_OF_WORK_FACTORY");
|
|
44
|
+
|
|
45
|
+
// src/lib/sqlite-unit-of-work.ts
|
|
46
|
+
var SqliteUnitOfWork = class {
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
48
|
+
constructor(db) {
|
|
49
|
+
this.db = db;
|
|
50
|
+
}
|
|
51
|
+
queries = [];
|
|
52
|
+
add(query) {
|
|
53
|
+
this.queries.push(query);
|
|
54
|
+
}
|
|
55
|
+
async execute() {
|
|
56
|
+
if (this.queries.length === 0) return;
|
|
57
|
+
const batch = [...this.queries];
|
|
58
|
+
this.queries = [];
|
|
59
|
+
try {
|
|
60
|
+
await this.db.transaction().execute(async (trx) => {
|
|
61
|
+
for (const query of batch) {
|
|
62
|
+
await trx.executeQuery(query);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
} catch (error) {
|
|
66
|
+
this.queries = [...batch, ...this.queries];
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/lib/provider.ts
|
|
73
|
+
function provideSqliteDb(filename) {
|
|
74
|
+
return [
|
|
75
|
+
provideDbAccessor(() => {
|
|
76
|
+
const db = createSqliteDb(filename);
|
|
77
|
+
return () => db;
|
|
78
|
+
}),
|
|
79
|
+
{
|
|
80
|
+
provide: UNIT_OF_WORK_FACTORY,
|
|
81
|
+
useFactory: () => {
|
|
82
|
+
const dbAccessor = inject(DB_ACCESSOR);
|
|
83
|
+
return () => new SqliteUnitOfWork(dbAccessor());
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
SqliteUnitOfWork,
|
|
90
|
+
createSqliteDb,
|
|
91
|
+
provideSqliteDb
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/lib/create-sqlite-db.ts", "../../di/src/lib/context.ts", "../../di/src/lib/inject.ts", "../../di/src/lib/injection-token.ts", "../../db/src/lib/db-accessor.ts", "../../db/src/lib/provider.ts", "../../db/src/lib/unit-of-work.ts", "../src/lib/sqlite-unit-of-work.ts", "../src/lib/provider.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Db } from '@cibule/db';\nimport Database from 'better-sqlite3';\nimport { Kysely, SqliteDialect } from 'kysely';\n\nexport function createSqliteDb<Schema>(filename: string): Db<Schema> {\n return new Kysely<Schema>({\n dialect: new SqliteDialect({\n database: new Database(filename),\n }),\n });\n}\n", "import type { Injector } from './injector';\n\nlet currentInjector: Injector | null = null;\n\nexport function getCurrentInjector(): Injector | null {\n return currentInjector;\n}\n\nexport function setCurrentInjector(injector: Injector | null): Injector | null {\n const previous = currentInjector;\n currentInjector = injector;\n return previous;\n}\n", "import { getCurrentInjector } from './context';\nimport type { InjectOptions } from './provider';\nimport type { Token } from './token';\n\nexport function inject<T>(token: Token<T>): T;\nexport function inject<T>(token: Token<T>, options: InjectOptions): T | null;\nexport function inject<T>(token: Token<T>, options?: InjectOptions): T | null {\n const injector = getCurrentInjector();\n\n if (!injector) {\n throw new Error('inject() must be called within an injection context (runInContext)');\n }\n\n return options ? injector.get(token, options) : injector.get(token);\n}\n", "export class InjectionToken<T> {\n declare readonly _brand: T;\n constructor(public readonly description: string) {}\n}\n", "import { InjectionToken } from '@cibule/di';\n\nimport type { Db } from './db';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type DbAccessor<Schema = any> = () => Db<Schema>;\n\nexport const DB_ACCESSOR = new InjectionToken<DbAccessor>('DB_ACCESSOR');\n", "import type { Provider } from '@cibule/di';\n\nimport type { DbAccessor } from './db-accessor';\nimport { DB_ACCESSOR } from './db-accessor';\n\nexport function provideDbAccessor<S>(factory: () => DbAccessor<S>): Provider {\n return { provide: DB_ACCESSOR, useFactory: factory };\n}\n", "import { InjectionToken } from '@cibule/di';\nimport type { CompiledQuery } from 'kysely';\n\nexport interface UnitOfWork {\n add<T>(query: CompiledQuery<T>): void;\n execute(): Promise<void>;\n}\n\nexport type UnitOfWorkFactory = () => UnitOfWork;\n\nexport const UNIT_OF_WORK_FACTORY = new InjectionToken<UnitOfWorkFactory>('UNIT_OF_WORK_FACTORY');\n", "import type { UnitOfWork } from '@cibule/db';\nimport type { CompiledQuery, Kysely } from 'kysely';\n\nexport class SqliteUnitOfWork implements UnitOfWork {\n private queries: CompiledQuery[] = [];\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public constructor(private readonly db: Kysely<any>) {}\n\n public add<T>(query: CompiledQuery<T>): void {\n this.queries.push(query);\n }\n\n public async execute(): Promise<void> {\n if (this.queries.length === 0) return;\n\n const batch = [...this.queries];\n this.queries = [];\n\n try {\n await this.db.transaction().execute(async trx => {\n for (const query of batch) {\n await trx.executeQuery(query);\n }\n });\n } catch (error: unknown) {\n this.queries = [...batch, ...this.queries];\n throw error;\n }\n }\n}\n", "import { DB_ACCESSOR, provideDbAccessor, UNIT_OF_WORK_FACTORY } from '@cibule/db';\nimport type { Provider } from '@cibule/di';\nimport { inject } from '@cibule/di';\n\nimport { createSqliteDb } from './create-sqlite-db';\nimport { SqliteUnitOfWork } from './sqlite-unit-of-work';\n\nexport function provideSqliteDb(filename: string): Provider[] {\n return [\n provideDbAccessor(() => {\n const db = createSqliteDb(filename);\n return () => db;\n }),\n {\n provide: UNIT_OF_WORK_FACTORY,\n useFactory: () => {\n const dbAccessor = inject(DB_ACCESSOR);\n return () => new SqliteUnitOfWork(dbAccessor());\n },\n },\n ];\n}\n"],
|
|
5
|
+
"mappings": ";AACA,OAAO,cAAc;AACrB,SAAS,QAAQ,qBAAqB;AAE/B,SAAS,eAAuB,UAA8B;AACnE,SAAO,IAAI,OAAe;AAAA,IACxB,SAAS,IAAI,cAAc;AAAA,MACzB,UAAU,IAAI,SAAS,QAAQ;AAAA,IACjC,CAAC;AAAA,EACH,CAAC;AACH;;;ACRA,IAAI,kBAAmC;AAEhC,SAAS,qBAAsC;AACpD,SAAO;AACT;;;ACAO,SAAS,OAAU,OAAiB,SAAmC;AAC5E,QAAM,WAAW,mBAAmB;AAEpC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,oEAAoE;AAAA,EACtF;AAEA,SAAO,UAAU,SAAS,IAAI,OAAO,OAAO,IAAI,SAAS,IAAI,KAAK;AACpE;;;ACdO,IAAM,iBAAN,MAAwB;AAAA,EAE7B,YAA4B,aAAqB;AAArB;AAAA,EAAsB;AACpD;;;ACIO,IAAM,cAAc,IAAI,eAA2B,aAAa;;;ACFhE,SAAS,kBAAqB,SAAwC;AAC3E,SAAO,EAAE,SAAS,aAAa,YAAY,QAAQ;AACrD;;;ACGO,IAAM,uBAAuB,IAAI,eAAkC,sBAAsB;;;ACPzF,IAAM,mBAAN,MAA6C;AAAA;AAAA,EAI3C,YAA6B,IAAiB;AAAjB;AAAA,EAAkB;AAAA,EAH9C,UAA2B,CAAC;AAAA,EAK7B,IAAO,OAA+B;AAC3C,SAAK,QAAQ,KAAK,KAAK;AAAA,EACzB;AAAA,EAEA,MAAa,UAAyB;AACpC,QAAI,KAAK,QAAQ,WAAW,EAAG;AAE/B,UAAM,QAAQ,CAAC,GAAG,KAAK,OAAO;AAC9B,SAAK,UAAU,CAAC;AAEhB,QAAI;AACF,YAAM,KAAK,GAAG,YAAY,EAAE,QAAQ,OAAM,QAAO;AAC/C,mBAAW,SAAS,OAAO;AACzB,gBAAM,IAAI,aAAa,KAAK;AAAA,QAC9B;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAgB;AACvB,WAAK,UAAU,CAAC,GAAG,OAAO,GAAG,KAAK,OAAO;AACzC,YAAM;AAAA,IACR;AAAA,EACF;AACF;;;ACvBO,SAAS,gBAAgB,UAA8B;AAC5D,SAAO;AAAA,IACL,kBAAkB,MAAM;AACtB,YAAM,KAAK,eAAe,QAAQ;AAClC,aAAO,MAAM;AAAA,IACf,CAAC;AAAA,IACD;AAAA,MACE,SAAS;AAAA,MACT,YAAY,MAAM;AAChB,cAAM,aAAa,OAAO,WAAW;AACrC,eAAO,MAAM,IAAI,iBAAiB,WAAW,CAAC;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-sqlite-db.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/create-sqlite-db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAIrC,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,CAMnE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAM3C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,CAc5D"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { UnitOfWork } from '@cibule/db';
|
|
2
|
+
import type { CompiledQuery, Kysely } from 'kysely';
|
|
3
|
+
export declare class SqliteUnitOfWork implements UnitOfWork {
|
|
4
|
+
private readonly db;
|
|
5
|
+
private queries;
|
|
6
|
+
constructor(db: Kysely<any>);
|
|
7
|
+
add<T>(query: CompiledQuery<T>): void;
|
|
8
|
+
execute(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=sqlite-unit-of-work.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-unit-of-work.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/sqlite-unit-of-work.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEpD,qBAAa,gBAAiB,YAAW,UAAU;IAI9B,OAAO,CAAC,QAAQ,CAAC,EAAE;IAHtC,OAAO,CAAC,OAAO,CAAuB;gBAGF,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAE5C,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI;IAI/B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAiBtC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cibule/db-sqlite",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://gitlab.com/LadaBr/cibule",
|
|
28
|
+
"directory": "packages/db-sqlite"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@cibule/db": "workspace:*",
|
|
35
|
+
"@cibule/di": "workspace:*",
|
|
36
|
+
"better-sqlite3": "^11.0.0",
|
|
37
|
+
"kysely": "^0.28.0"
|
|
38
|
+
}
|
|
39
|
+
}
|