Files
skills/docs/api-stack/api/api-plugin-site/src/service/db-port.md
2026-05-29 08:20:56 +01:00

2.2 KiB

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

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

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<T>(sql, params?): Promise<T[]> — positional binds ($p0...).
    • create<T>(table, data): Promise<T & { id: string }> — typed create.
    • update<T>(table, id, data): Promise<T | null> — 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.