zanith

Postgres extensions

Typed wrappers for the four extensions Zanith treats as first-class. Compose them inside the relational query builder; the engine emits the right operator for the right dialect and parameterises every value.

Declaring an extension

emitCreateExtension emits the DDL the migration runner uses; you rarely need to call it by hand. KNOWN_EXTENSIONS lists the ones the engine has typed wrappers for.

TS
import { emitCreateExtension } from 'zanith';
 
await adapter.executeRaw(emitCreateExtension('pgvector'));
// CREATE EXTENSION IF NOT EXISTS "vector";

pgvector — embeddings

Five distance helpers that produce expressions usable in where, orderBy, and select callbacks.

HelperOperatorUse when
vectorLit(values)'[1, 2, 3]'::vectorBind a query vector as a parameter.
l2Distance(a, b)a <-> bEuclidean — geometric similarity.
innerProductDistance(a, b)a <#> bNegative inner product.
cosineDistance(a, b)a <=> bDirection-only — the default for embeddings.
l1Distance(a, b)a <+> bManhattan — sparse / count vectors.
TS
import { cosineDistance, vectorLit, fieldRef } from 'zanith';
 
const nearest = await db.document.query()
.select(({ document }) => ({
id: document.id,
title: document.title,
distance: cosineDistance(document.embedding, vectorLit(queryEmbedding)),
}))
.orderBy(({ document }) =>
cosineDistance(document.embedding, vectorLit(queryEmbedding)).asc(),
)
.limit(10)
.execute();

pg_trgm — trigram similarity

HelperSQL
trigramSimilar(a, b)a % b — boolean above the pg_trgm.similarity_threshold.
trigramDistance(a, b)a <-> b — distance, lower is closer.
wordSimilar(a, b)a <% b — best-substring match.
similarity(a, b)similarity(a, b) — score in [0, 1].
wordSimilarity(a, b)word_similarity(a, b).
TS
import { trigramSimilar, similarity, lit } from 'zanith';
 
const fuzzy = await db.user.query()
.where(({ user }) => trigramSimilar(user.name, lit('alic')))
.orderBy(({ user }) => similarity(user.name, lit('alic')).desc())
.limit(10)
.execute();

pgcrypto — hashes, HMAC, encryption, UUIDs

HelperSQL
genRandomUuid()gen_random_uuid()
digest(data, type)digest(data, type)'sha256' etc.
hmac(data, key, type)hmac(data, key, type)
crypt(password, salt)crypt(password, salt) — bcrypt-style hashing.
genSalt(algorithm, rounds?)gen_salt('bf', 12)
pgpSymEncrypt(data, key)pgp_sym_encrypt(data, key)
pgpSymDecrypt(data, key)pgp_sym_decrypt(data, key)
TS
import { crypt, genSalt, lit } from 'zanith';
 
await db.user.insert({
email: '[email protected]',
passwordHash: crypt(lit(password), genSalt(lit('bf'), lit(12))),
}).execute();

pg_cron — scheduled jobs

pg_cron runs SQL on a schedule from inside Postgres itself. The wrappers produce CompiledQuery objects so you can schedule, list, and unschedule jobs from your application.

HelperPurpose
cronSchedule(name, schedule, command)cron.schedule(name, schedule, command)
cronScheduleInDatabase(name, schedule, command, database)Same, but pin to another database.
cronUnschedule(name)cron.unschedule(name)
cronUnscheduleById(jobId)cron.unschedule(jobid)
cronListJobs()SELECT … FROM cron.job
cronJobHistory(name, limit?)SELECT … FROM cron.job_run_details WHERE jobid = …
TS
import { cronSchedule, cronJobHistory } from 'zanith';
 
// Nightly cleanup at 02:30 UTC.
await adapter.execute(cronSchedule(
'cleanup-expired-sessions',
'30 2 * * *',
"DELETE FROM sessions WHERE expires_at < now()",
));
 
// Inspect the last 50 runs:
const { rows } = await adapter.execute(cronJobHistory('cleanup-expired-sessions'));

Composability with the search system

search() already composes vector and trigram inside one ranked query. Reach for the standalone helpers when you need something search()can't express — distance in the projection, an extra rank tweak in orderBy, or a fuzzy join condition.