first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -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.