Files
skills/docs/api-stack/api/api-db-adapter/src/factory/create-db-adapter.md
2026-05-29 08:20:56 +01:00

2.9 KiB

factory/create-db-adapter — direct-surface adapter factory

(no submodules)

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

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

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.