first commit
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
# `factory/create-db-adapter` — direct-surface adapter factory
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`createDbAdapter` is the public entry point for host code that wants to wire
|
||||
the `@suaveplan/db` engine adapters to the plugin
|
||||
`AdminDatabaseLike` / `TenantScopedDatabaseLike` surfaces. It composes three
|
||||
pieces from this package — the options validator, the engine registry, and
|
||||
the tenant-scope wrapper — into a single callable that delegates engine
|
||||
identity to the open `DatabaseEngineRegistry`.
|
||||
|
||||
The result object exposes:
|
||||
|
||||
- `admin` — the unscoped `AdminDatabaseLike` (used by migrations and admin
|
||||
endpoints).
|
||||
- `scoped(tenantId)` — produces a fresh `TenantScopedDatabaseLike` wrapper
|
||||
over the same admin connection. The wrapper is stateless beyond the
|
||||
rewrite contract, so one admin connection can back many tenant scopes
|
||||
concurrently.
|
||||
- `close()` — closes the underlying admin connection.
|
||||
|
||||
## Features
|
||||
|
||||
- Options are parsed once at factory time; the rest of the API is typed
|
||||
against the *post-parse* `DbAdapterOptions`.
|
||||
- Engine lookup is delegated to `buildEngineAdapter`, so any
|
||||
declaration-merged engine works automatically.
|
||||
- Tenant scoping config (`tenantColumn`, `autoInjectInserts`) flows from
|
||||
the parsed options into every `scoped()` call — no per-call repetition.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createDbAdapter } from "@suaveplan/api-db-adapter/adapter";
|
||||
import { registerEngine } from "@suaveplan/api-db-adapter/engine-registry";
|
||||
|
||||
registerEngine("sqlite", buildSqliteEngineFactory());
|
||||
|
||||
const db = await createDbAdapter({ engine: "sqlite", url: ":memory:" });
|
||||
const admin = db.admin;
|
||||
const acme = db.scoped("acme" as TenantId);
|
||||
const rows = await acme.query("SELECT * FROM users");
|
||||
await db.close();
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
const db = await createDbAdapter({
|
||||
engine: "postgres",
|
||||
url: "postgres://app@db.local/app",
|
||||
tenantColumn: "org_id",
|
||||
autoInjectInserts: false,
|
||||
pool: { min: 2, max: 16, idleMs: 60_000 },
|
||||
});
|
||||
|
||||
const tx = await db.scoped(tenantId).transaction!(async (tx) => {
|
||||
await tx.execute(
|
||||
"INSERT INTO invoices (id, org_id, amount) VALUES (?, ?, ?)",
|
||||
["inv_1", tenantId, 100]
|
||||
);
|
||||
return await tx.query<{ id: string }[]>("SELECT id FROM invoices");
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `createDbAdapter(input: DbAdapterOptionsInput): Promise<DbAdapter>`.
|
||||
- `DbAdapter.admin: AdminDatabaseLike`.
|
||||
- `DbAdapter.scoped(tenantId: TenantId): TenantScopedDatabaseLike`.
|
||||
- `DbAdapter.close(): Promise<void>`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The factory does NOT register engines on import — it expects the host or a
|
||||
downstream adapter package to populate the registry before the first call.
|
||||
This shape keeps `@suaveplan/api-db-adapter` universally importable and
|
||||
prevents engine deps from leaking into bundles that never use them. Errors
|
||||
surface synchronously where possible (options validation, engine lookup);
|
||||
engine handshake errors arrive as the promise rejection.
|
||||
Reference in New Issue
Block a user