Skip to content

Executor-generic DB layer: SQLite/Postgres duplication grows with every feature #158

Description

@haasonsaas

Problem

The API's database layer duplicates logic per-backend via paired _on_connection-suffixed functions (one code path built against a SQLite connection, one against a Postgres connection) rather than a single executor-generic implementation. This duplication is already large and grows with every new feature, since each new query or mutation needs to be written and tested twice.

Evidence

Occurrences of the _on_connection naming pattern, current main:

  • crates/sandboxwich-api/src/handlers/leases.rs — 64 occurrences
  • crates/sandboxwich-api/src/handlers/snapshots.rs — 30 occurrences
  • crates/sandboxwich-api/src/reconcile.rs — 27 occurrences
  • crates/sandboxwich-api/src/handlers/sandboxes.rs — 24 occurrences

That's 145 occurrences across just four files, not counting handlers/jobs.rs, handlers/workers.rs, handlers/operations.rs, and others that likely follow the same pattern.

Suggested approach

Investigate whether sqlx's Executor trait (generic over &mut SqliteConnection / &mut PgConnection, or an Any pool) can collapse the paired functions into one generic-over-executor implementation, keeping only the genuinely backend-divergent SQL (e.g. INSERT ... ON CONFLICT syntax differences, RETURNING support, atomic-counter upsert dialects) as explicit branches. This is a larger refactor and should land incrementally, file-by-file, each covered by the existing SQLite + Postgres contract-test suites so behavior parity is provable at each step, per the AGENTS.md guidance on keeping every change gate-clean.

Relationship to ROADMAP

Not a promotion-gate blocker directly, but every gate (Conformance in particular, "SQLite and PostgreSQL contract suites pass on the release commit") gets more expensive to keep true as this duplication compounds.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions