Dialect parity

runDialectParity — a fixed scenario suite that proves a SQL backend behaves identically to the others. For dialect-package authors and apps with hand-written portable SQL.

When you need this

Most apps never touch this page. The framework's DSL already hides every cross-dialect difference, and a unit test on the in-memory store proves your handler logic. Reach for runDialectParity only when you have code that talks to a real database in a dialect-specific way:

  • You're authoring a new @voltro/sql-* dialect package and need to prove it before plugging it into loadDialect().
  • Your app drops to unsafe() SQL or custom store logic that must stay portable across the backends you ship on.

runDialectParity

runDialectParity(fixture) registers a vitest suite (describe('dialect parity: <name>')) that runs a fixed scenario set against the database your fixture stands up — and asserts identical behaviour on each. It's exported from the @voltro/testing/dialect subpath — the only part of @voltro/testing that imports vitest, so makeTestContext consumers carry no vitest peer. The scenarios cover the contract the DSL relies on:

  • DDL idempotency (re-applying the schema is a no-op)
  • insert / query round-trip, update post-image, delete
  • onChange fires insert + update + delete events
  • transactional rolls back on throw (and drops queued change events) / commits and drains events in order
  • upsert (insert then update-on-conflict, no duplicate)
  • updateMany with a predicate, and the atomic compare-and-set (the wakeup-claim pattern)
  • retryFilter returns a stable 'retry' | 'noRetry' decision

The harness intentionally does not bundle docker setup — that lives next to the dialect, so the parity packages' devDeps stay minimal. Your fixture owns the lifecycle (scratch docker Postgres, temp-file SQLite, …).

// sql-postgres/__tests__/parity.test.ts
import { runDialectParity, applySchema } from '@voltro/testing/dialect'
import { postgresDialect } from '../src/index'

runDialectParity({
  dialect: postgresDialect,
  name: 'postgres (scratch docker)',
  setup:    async () => { /* stand up a clean scratch database */ },
  teardown: async () => { /* drop it */ },
  make:     async () => ({
    store:   /* the live DataStore for this scenario */,
    migrate: (tables) => /* applySchema(tables, dialect.id) against the same runtime */,
    dispose: async () => { /* close store, drop scratch state */ },
  }),
})

The fixture contract

DialectFixture:

Field Meaning
dialect The SqlDialect under test (its id, retryFilter, etc.).
name? Label for the test output (defaults to dialect.id).
setup Runs before each scenario — give it a clean slate.
teardown Runs after each scenario.
make Returns a DialectFixtureSession for the scenario.

DialectFixtureSession:

Field Meaning
store The live DataStore the scenarios drive.
migrate(tables) Apply applySchema(tables, dialect.id) against the same runtime the store uses, so DDL and DML hit the same database.
dispose() Tear the session down (close store, drop scratch DB).

applySchema is re-exported from @voltro/testing/dialect (the same subpath as runDialectParity, not the root entry) so a fixture can build its migrate without pulling @voltro/database/sql separately. Once a dialect green-checks the harness, it's ready for loadDialect().