Validation

Validation

Attach a Standard Schema validator (for example, Zod) to validate execution result after SQL runs.

Why It Exists

Validation adds a runtime contract for query results. SQL can be syntactically correct but still return unexpected shapes. Validation catches that mismatch before data flows deeper into your app.

Runtime safety

Ensure row shape is exactly what your service layer expects.

Better debugging

Validation failures make data contract breaks obvious and fast to diagnose.

Shared contract

Same schema can represent both expected runtime data and docs for your team.

Install Validator

Pick any validator compatible with Standard Schema.

npm install zod
# optional alternatives (Standard Schema compatible)
npm install valibot arktype @effect/schema

Supported Libraries

This project accepts Standard Schema implementations (see standardschema.dev). In practice, any library exposing the Standard Schema contract can be used.

LibraryStatusNotes
ZodRecommendedUsed in repository tests and examples.
ValibotSupported via Standard SchemaGood option for lightweight, composable validation.
ArkTypeSupported via Standard SchemaGreat for expressive type-first schema declarations.
Effect SchemaSupported via Standard SchemaStrong option if you already use Effect in your app architecture.

QueryBuilder Validation

Call setValidation on a query. Runtime metapassed to execute(meta) is forwarded to the execution handler.

import { z } from "zod"

const q = sqlBuilder()
  .setFormatParamHandler("pg")
  .setExecutionHandler(async () => [{ name: "John", age: 20 }])

const result = await q
  .select("*")
  .from(q.t("users"))
  .setValidation(
    z.array(
      z.object({
        name: z.string(),
        age: z.number(),
      }),
    ),
  )
  .execute({ requestId: "docs-1" })

Alternative example: Valibot

import * as v from "valibot"

const usersSchema = v.array(
  v.object({
    name: v.string(),
    age: v.number(),
  }),
)

const result = await q
  .select("*")
  .from(q.t("users"))
  .setValidation(usersSchema)
  .execute()

Alternative example: ArkType

import { type } from "arktype"

const usersSchema = type("{ name: string, age: number }[]")

const result = await q
  .select("*")
  .from(q.t("users"))
  .setValidation(usersSchema)
  .execute()

sqlSchema Validation

You can also define validator once at schema query registration withvalidation(...).

import { z } from "zod"

const sch = sqlSchema().setQuery(
  "getMagma",
  sqlSchema()
    .set
    .query(q.select("*").from(q.t("users")))
    .validation(
      z.array(
        z.object({
          name: z.string(),
          age: z.number(),
        }),
      ),
    ),
)

const result = await sch.query("getMagma").execute({ requestId: "schema-1" })

Validation Errors

If execution result does not satisfy the validation schema, execution throws an error.

const qValidate = sqlBuilder()
  .setFormatParamHandler("pg")
  .setExecutionHandler(async () => [{ id: 10 }])

const builder = qValidate
  .select("*")
  .from(qValidate.t("users"))
  .setValidation(z.array(z.object({ id: z.string() })))

await builder.execute()
// throws when validation fails