Files
2026-05-27 23:47:53 +01:00

3.6 KiB

crud

(no submodules)

Purpose

crud exposes the typed record-level CRUD primitives (create, select, update, delete, selectAll) used by SurrealAdapter. Splitting them into a standalone module keeps adapter.ts under the 300-line hard limit and lets advanced consumers reach for the helpers directly when they already hold a SurrealClientLike reference.

Each helper is a plain async function that takes the client as its first positional argument — it never reads adapter state — which makes the CRUD layer trivially testable with a real fake client and free of hidden lifecycle coupling.

Features

  • surrealCreate — INSERT INTO <table> CONTENT $data (works around the surrealdb.js v2+ create bug)
  • surrealSelect / surrealUpdate / surrealDelete — record-id-scoped operations using type::thing($table, $id)
  • surrealSelectAll — full-table read
  • Driver errors are normalised through wrapQueryError so every failure surfaces as a SurrealError with a stable code
  • AbortSignal is honoured at the start of every call via signal.throwIfAborted()

Usage: Basic Example

import { surrealCreate, surrealSelect } from "@suaveplan/surrealdb/adapter/crud";

const created = await surrealCreate(client, "user", { name: "Alice" });
const fetched = await surrealSelect<{ name: string }>(client, "user", "alice");

Usage: Advanced Example

import {
    surrealSelectAll,
    surrealUpdate,
    surrealDelete,
} from "@suaveplan/surrealdb/adapter/crud";

const all = await surrealSelectAll<{ id: string; archived: boolean }>(client, "doc");
for (const doc of all) {
    if (!doc.archived) continue;
    const ac = new AbortController();
    setTimeout(() => ac.abort(), 5000);
    await surrealUpdate(client, "doc", doc.id, { archived: false }, { signal: ac.signal });
    await surrealDelete(client, "tombstone", doc.id, { signal: ac.signal });
}

API Reference

surrealCreate<T>(client, table, data, opts?): Promise<T & { id: string }>

Throws SurrealError(QUERY_FAILED) when the driver returns zero rows or any other error.

surrealSelect<T>(client, table, id, opts?): Promise<T | null>

Returns null when no row matches. Throws SurrealError(QUERY_FAILED) on driver errors.

surrealUpdate<T>(client, table, id, data, opts?): Promise<T | null>

Returns null when no row matched. Throws SurrealError(QUERY_FAILED) on driver errors.

surrealDelete(client, table, id, opts?): Promise<void>

Throws SurrealError(QUERY_FAILED) on driver errors.

surrealSelectAll<T>(client, table, opts?): Promise<T[]>

Returns the row array (possibly empty). Throws SurrealError(QUERY_FAILED) on driver errors.

Implementation Notes

  • Each helper accepts a SurrealClientLike rather than the full adapter so consumers can reuse them with custom client wrappers, mocks, or in transactional bodies that already hold the client.
  • AbortSignal is consulted only at the entry point; the underlying driver does not currently accept a per-call signal, so once the await client.query(...) is in flight cancellation cannot interrupt it. Callers needing harder cancellation should race the call against a timeout external to the helper.
  • All error paths unify on wrapQueryError, except surrealCreate which can throw a code-specific SurrealError(QUERY_FAILED) when the row array is empty — that case is distinguishable from a thrown driver error because it carries the exact INSERT INTO <table> returned no rows message.
  • The flattenRows helper from query-helpers shields callers from the surrealdb.js v2 [[...]] result-wrapping detail.