# `service/db-port.ts` ## Purpose Declares `SiteDb`, the structural database port that `SiteService` and `DomainResolverService` consume. suaveplan's foundation `DatabaseAdapter` (`@suaveplan/db`) only owns `query` / `execute`, so the typed CRUD surface (`create`, `update`) we need for `site` records is sourced from `@suaveplan/surrealdb`'s `SurrealAdapter`. Centralising the port here lets the services depend on a single structural shape rather than `SurrealAdapter` directly, which keeps the unit tests free of testcontainer requirements and keeps the production wiring honest: any `SurrealAdapter` instance satisfies this shape by construction. ## Features - One structural interface — `SiteDb` — exposing `query` (positional bindings), `create` (typed), `update` (typed). - No runtime imports — pure type module. - Lets tests supply minimal fakes without crafting a full `DatabaseAdapter`. ## Usage: Basic ```ts import type { SiteDb } from "@suaveplan/api-plugin-site/service/db-port"; const fake: SiteDb = { query: async () => [], create: async (_t, d) => ({ ...d, id: "site:1" }), update: async () => null, }; ``` ## Usage: Advanced ```ts import type { SurrealAdapter } from "@suaveplan/surrealdb"; import type { SiteDb } from "@suaveplan/api-plugin-site/service/db-port"; // Production wiring — the live SurrealAdapter satisfies SiteDb structurally. function wire(db: SurrealAdapter): SiteDb { return db; } ``` ## API Reference - `interface SiteDb` — - `query(sql, params?): Promise` — positional binds (`$p0...`). - `create(table, data): Promise` — typed create. - `update(table, id, data): Promise` — typed merge. ## Implementation Notes - `query` bindings are positional because the `DatabaseAdapter.query` signature is `(sql, params?: readonly unknown[])`. The site plugin's SurQL statements are written with `$p0`, `$p1`, ... accordingly. - The port deliberately omits transaction / migrate / connect surface — services don't need it. Adding new methods to the port is a breaking change and follows the OpenSpec workflow. - The port is structural — adopters do not need to extend or implement an interface explicitly.