@kubun/db 0.8.1 → 0.10.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.
Files changed (3) hide show
  1. package/lib/db.d.ts +16 -1
  2. package/lib/db.js +1 -1
  3. package/package.json +5 -5
package/lib/db.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { Adapter, ColumnTypes, Functions } from '@kubun/db-adapter';
2
2
  import { type Logger } from '@kubun/logger';
3
- import { Kysely, type Migration } from 'kysely';
3
+ import { Kysely } from 'kysely';
4
+ import { type Migration } from 'kysely/migration';
4
5
  export type MigrationContext = {
5
6
  types: ColumnTypes;
6
7
  functions: Functions;
@@ -14,6 +15,20 @@ export type StoreDefinition<Tables, API> = {
14
15
  export type StoreProvider<Stores extends Record<string, unknown> = Record<string, unknown>> = {
15
16
  getStore<S extends keyof Stores & string>(name: S): Promise<Stores[S]>;
16
17
  onCommit(fn: () => void): void;
18
+ /**
19
+ * Run `fn` against a `StoreProvider` that scopes its writes to a transaction.
20
+ *
21
+ * On `KubunDB`, opens a fresh DB transaction and provides a transactional
22
+ * `tx` provider; the outer provider's `onCommit` hooks fire after commit.
23
+ *
24
+ * On a transactional `tx` provider obtained from a parent
25
+ * `withTransaction` call, this method runs `fn` inline with `this` as the
26
+ * nested `tx`. The underlying driver does not nest transactions
27
+ * (no savepoints), so atomicity is inherited from the outer transaction
28
+ * — a throw in `fn` rolls the whole outer transaction back, exactly the
29
+ * semantics callers expect for "register + bind atomically".
30
+ */
31
+ withTransaction<NestedStores extends Record<string, unknown>, R>(fn: (tx: StoreProvider<NestedStores>) => Promise<R>): Promise<R>;
17
32
  };
18
33
  export type KubunDBParams = {
19
34
  adapter: Adapter;
package/lib/db.js CHANGED
@@ -1 +1 @@
1
- import{getKubunLogger as t}from"@kubun/logger";import{Kysely as e,Migrator as r,ParseJSONResultsPlugin as i}from"kysely";export class KubunDB{#t;#e;#r;#i=new Map;#s=new Map;#a=new Map;constructor(r){this.#t=r.adapter,this.#e=new e({dialect:this.#t.dialect,plugins:[new i]}),this.#r=r.logger??t("db")}get adapter(){return this.#t}register(t){let e=this.#a.get(t.name);if(null!=e){e!==t&&this.#r.warn('store "{name}" registered with different definition, ignoring',{name:t.name});return}this.#a.set(t.name,t)}async getStore(t){if(await this.#o(t),!this.#s.has(t)){let e=this.#a.get(t);if(null==e)throw Error(`Store "${t}" is not registered`);this.#s.set(t,e.createAPI(this.#e,this.#t))}return this.#s.get(t)}onCommit(t){t()}async withTransaction(t){await Promise.all(Array.from(this.#a.keys()).map(t=>this.#o(t)));let e=[],r=await this.#e.transaction().execute(async r=>{let i=new Map;return await t({getStore:async t=>{if(!i.has(t)){let e=this.#a.get(t);if(null==e)throw Error(`Store "${t}" is not registered`);i.set(t,e.createAPI(r,this.#t))}return i.get(t)},onCommit:t=>{e.push(t)}})});for(let t of e)t();return r}async close(){await this.#e.destroy(),this.#r.info("closed")}async #o(t){let e=this.#i.get(t);return null==e&&(e=this.#n(t).catch(e=>{throw this.#i.delete(t),e}),this.#i.set(t,e)),e}async #n(t){let e=this.#a.get(t);if(null==e)throw Error(`Store "${t}" is not registered`);for(let t of e.dependsOn??[])await this.#o(t);let i="function"==typeof e.migrations?e.migrations({types:this.#t.types,functions:this.#t.functions}):e.migrations;if(0===Object.keys(i).length)return;let s=new r({db:this.#e,provider:{getMigrations:()=>Promise.resolve(i)},migrationTableName:`kubun_${t}_migration`,migrationLockTableName:`kubun_${t}_migration_lock`}),a=await s.migrateToLatest();if(null!=a.error)throw a.error;this.#r.info("store {name} migrations complete",{name:t})}}
1
+ import{getKubunLogger as t}from"@kubun/logger";import{Kysely as e,ParseJSONResultsPlugin as r}from"kysely";import{Migrator as i}from"kysely/migration";export class KubunDB{#t;#e;#r;#i=new Map;#s=new Map;#a=new Map;constructor(i){this.#t=i.adapter,this.#e=new e({dialect:this.#t.dialect,plugins:[new r]}),this.#r=i.logger??t("db")}get adapter(){return this.#t}register(t){let e=this.#a.get(t.name);if(null!=e){e!==t&&this.#r.warn('store "{name}" registered with different definition, ignoring',{name:t.name});return}this.#a.set(t.name,t)}async getStore(t){if(await this.#o(t),!this.#s.has(t)){let e=this.#a.get(t);if(null==e)throw Error(`Store "${t}" is not registered`);this.#s.set(t,e.createAPI(this.#e,this.#t))}return this.#s.get(t)}onCommit(t){t()}async withTransaction(t){await Promise.all(Array.from(this.#a.keys()).map(t=>this.#o(t)));let e=[],r=await this.#e.transaction().execute(async r=>{let i=new Map,s={getStore:async t=>{if(!i.has(t)){let e=this.#a.get(t);if(null==e)throw Error(`Store "${t}" is not registered`);i.set(t,e.createAPI(r,this.#t))}return i.get(t)},onCommit:t=>{e.push(t)},withTransaction:async t=>await t(s)};return await t(s)});for(let t of e)t();return r}async close(){await this.#e.destroy(),this.#r.info("closed")}async #o(t){let e=this.#i.get(t);return null==e&&(e=this.#n(t).catch(e=>{throw this.#i.delete(t),e}),this.#i.set(t,e)),e}async #n(t){let e=this.#a.get(t);if(null==e)throw Error(`Store "${t}" is not registered`);for(let t of e.dependsOn??[])await this.#o(t);let r="function"==typeof e.migrations?e.migrations({types:this.#t.types,functions:this.#t.functions}):e.migrations;if(0===Object.keys(r).length)return;let s=new i({db:this.#e,provider:{getMigrations:()=>Promise.resolve(r)},migrationTableName:`kubun_${t}_migration`,migrationLockTableName:`kubun_${t}_migration_lock`}),a=await s.migrateToLatest();if(null!=a.error)throw a.error;this.#r.info("store {name} migrations complete",{name:t})}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubun/db",
3
- "version": "0.8.1",
3
+ "version": "0.10.0",
4
4
  "license": "see LICENSE.md",
5
5
  "keywords": [],
6
6
  "type": "module",
@@ -15,12 +15,12 @@
15
15
  ],
16
16
  "sideEffects": false,
17
17
  "dependencies": {
18
- "kysely": "^0.28.16",
19
- "@kubun/db-adapter": "^0.8.1",
20
- "@kubun/logger": "^0.8.0"
18
+ "kysely": "^0.29.2",
19
+ "@kubun/db-adapter": "^0.10.0",
20
+ "@kubun/logger": "^0.10.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@kubun/db-better-sqlite": "^0.8.1"
23
+ "@kubun/db-better-sqlite": "^0.10.0"
24
24
  },
25
25
  "scripts": {
26
26
  "build:clean": "del lib",