43 lines · 1.4 KB
import { env } from "cloudflare:workers";
import { all, first } from "./db";
import { countD1, timed } from "./perf";

const countReplica = (ms: number) => countD1(ms, true);

type D1Value = string | number | null;

function session(): D1DatabaseSession | null {
  const db = (env as { DB?: D1Database }).DB;
  return typeof db?.withSession === "function" ? db.withSession("first-unconstrained") : null;
}

/**
 * Directory reads that tolerate a few seconds of replica lag (account name search, display names) go through the
 * D1 Sessions API so read replication can serve them. Anything that gates access, filters by visibility (a repo
 * just made private must vanish at once) or follows a write uses `first`/`all` from ./db, which always hit the
 * primary. Falls back to the primary where sessions are unavailable.
 */
export const replica = {
  async first<T>(sql: string, ...params: D1Value[]): Promise<T | null> {
    const live = session();
    if (!live) return first<T>(sql, ...params);
    return timed(countReplica, () =>
      live
        .prepare(sql)
        .bind(...params)
        .first<T>(),
    );
  },
  async all<T>(sql: string, ...params: D1Value[]): Promise<T[]> {
    const live = session();
    if (!live) return all<T>(sql, ...params);
    const result = await timed(countReplica, () =>
      live
        .prepare(sql)
        .bind(...params)
        .all<T>(),
    );
    return result.results;