first commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# `engine-registry` — open registry mapping engine names to factories
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The engine registry is the extension point that lets `api-db-adapter` stay
|
||||
universally importable while still supporting per-engine concrete adapters
|
||||
(SQLite, Postgres, SurrealDB, plus declaration-merged third-party engines).
|
||||
The package itself ships zero engines pre-installed. Host code or the
|
||||
downstream adapter package calls `registerEngine(name, factory)` once at
|
||||
process boot; every subsequent `createDbAdapter({ engine: name, ... })` call
|
||||
delegates to that factory.
|
||||
|
||||
This shape avoids three failure modes: pulling `bun:sqlite` into a browser
|
||||
bundle, pulling `pg` into a worker, and pulling `surrealdb.js` into a CLI.
|
||||
|
||||
## Features
|
||||
|
||||
- `registerEngine(name, factory)` — register or replace a factory.
|
||||
- `unregisterEngine(name)` — primarily for test isolation.
|
||||
- `getEngineFactory(name)` — read-only lookup.
|
||||
- `listEngines()` — snapshot of all currently-registered names.
|
||||
- `buildEngineAdapter(options)` — high-level: look up + invoke + return the
|
||||
constructed `AdminDatabaseLike`. Throws `DB_ADAPTER.ENGINE_UNSUPPORTED`
|
||||
if the engine name has no factory.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
registerEngine,
|
||||
buildEngineAdapter,
|
||||
} from "@suaveplan/api-db-adapter/engine-registry";
|
||||
import { SqliteAdapter } from "@suaveplan/db-sqlite";
|
||||
|
||||
registerEngine("sqlite", async (options) => {
|
||||
const adapter = new SqliteAdapter({ filename: options.url });
|
||||
await adapter.connect();
|
||||
return adaptToAdminDatabaseLike(adapter, "sqlite");
|
||||
});
|
||||
|
||||
const admin = await buildEngineAdapter({
|
||||
engine: "sqlite",
|
||||
url: ":memory:",
|
||||
tenantColumn: "tenant_id",
|
||||
autoInjectInserts: true,
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { registerEngine } from "@suaveplan/api-db-adapter/engine-registry";
|
||||
|
||||
// declaration-merge a new engine
|
||||
declare module "@suaveplan/api-types/db" {
|
||||
interface DatabaseEngineRegistry {
|
||||
readonly cockroach: true;
|
||||
}
|
||||
}
|
||||
|
||||
registerEngine("cockroach", async (options) => {
|
||||
// build a CockroachDB-backed AdminDatabaseLike from options
|
||||
return buildCockroachAdmin(options);
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `EngineFactory: (options: DbAdapterOptions) => Promise<AdminDatabaseLike>`.
|
||||
- `registerEngine(name, factory): void` — register/replace.
|
||||
- `unregisterEngine(name): boolean` — remove; returns `true` if removed.
|
||||
- `getEngineFactory(name): EngineFactory | undefined`.
|
||||
- `listEngines(): readonly string[]`.
|
||||
- `buildEngineAdapter(options): Promise<AdminDatabaseLike>` — throws
|
||||
`DbAdapterError` with code `DB_ADAPTER.ENGINE_UNSUPPORTED` if the engine
|
||||
name was never registered.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The registry is a process-wide singleton kept in module scope. That is the
|
||||
correct shape for a sealed-once-at-boot capability map. Tests use
|
||||
`unregisterEngine` for isolation; concurrent registration with the same name
|
||||
is well-defined (last writer wins). The error thrown on lookup miss includes
|
||||
`details.known: string[]` so operator log lines surface the typo immediately.
|
||||
Reference in New Issue
Block a user