Skip to main content

QueryBuilder (Raw SQL)

The QueryBuilder is a low-level, Knex-like API for building raw SQL queries. Access it via sql.query('table'). It's suitable for performance crucial database queries since there is no serialization and the driver output is directly returned from the query.

Key Features

  • Works with any table (even without a model)
  • Not type-safe (returns plain objects)
  • Flexible for migrations, admin scripts, or advanced SQL
  • Supports filtering, selecting, joining, pagination, CTEs, truncate, softDelete, and more

Best Practice: Use QueryBuilder for raw SQL, migrations, or when want the max performance in a query. For app logic, prefer the ModelQueryBuilder.

Example Usage

import { sql } from "hysteria-orm";
const users = await sql.query("users").where("status", "active").many();

Filtering

const users = await sql.query("users").where("age", ">", 18).many();

Selecting Columns

const names = await sql.query("users").select("name").many();

Pagination

const page = await sql.query("users").paginate(1, 10);
console.log(page.data, page.paginationMetadata);

Joins

const postsWithUsers = await sql
.query("posts")
.join("users", "posts.userId", "users.id")
.select("posts.*", "users.name")
.many();

CTEs (Common Table Expressions)

const users = await sql
.query("users")
.with("active_users", (cte) =>
cte.newCte("users_cte", (b) => b.select("name").where("isActive", true))
)
.many();

Truncate

await sql.query("users").truncate();

Soft Delete

await sql.query("users").softDelete({ column: "deleted_at" });

Limitations

  • No type safety: results are plain objects
  • No decorator or relation support
  • Use with caution in app logic

Comparison to ModelQueryBuilder

  • Type Safety: QueryBuilder is not typed, ModelQueryBuilder is.
  • Decorator/Relation Support: Only ModelQueryBuilder supports model decorators and relations.
  • Use Case: Use QueryBuilder for raw SQL, migrations, or admin scripts.

Full API Reference

Filtering

  • where, orWhere, andWhere, whereIn, whereNotIn, whereNull, whereNotNull, whereBetween, whereNot, whereLike, whereNotLike, andWhereLike, andWhereNotLike, orWhereLike, orWhereNotLike, whereExists, whereNotExists
await sql.query("users").where("email", "like", "%@example.com").many();
await sql.query("users").whereIn("status", ["active", "pending"]).many();
await sql.query("users").whereNull("deletedAt").many();
await sql.query("users").whereBetween("age", [18, 30]).many();

Subqueries & Nested Conditions

  • whereSubQuery, andWhereSubQuery, orWhereSubQuery, whereBuilder, andWhereBuilder, orWhereBuilder
await sql
.query("users")
.whereSubQuery("id", (sub) =>
sub.select("userId").from("posts").where("published", true)
)
.many();
await sql
.query("users")
.whereBuilder((qb) => qb.where("age", ">", 18).orWhere("isActive", true))
.many();

Joins

  • join, leftJoin, rightJoin, innerJoin
await sql.query("posts").join("users", "posts.userId", "users.id").many();

Group By & Having

  • groupBy, having
await sql.query("users").groupBy("status").having("COUNT(*)", ">", 1).many();

Unions

  • union, unionAll
await sql
.query("users")
.select("name")
.union("SELECT name FROM users")
.many();

Aggregates

  • getCount, getMax, getMin, getAvg, getSum
const count = await sql.query("users").getCount();
const maxAge = await sql.query("users").getMax("age");

Select & Raw Select

  • select, selectRaw, clearSelect
await sql.query("users").select("name", "email").many();
await sql.query("users").selectRaw("count(*) as count").first();
await sql.query("users").clearSelect().many();

Annotations

  • annotate, removeAnnotations, clearRemoveAnnotations
await sql.query("users").annotate("COUNT(*)", "count").first();
await sql.query("users").removeAnnotations().first();

Pluck

  • pluck
const names = await sql.query("users").pluck("name");

Pagination

  • paginate, limit, offset
const page = await sql.query("users").paginate(1, 10);
await sql.query("users").limit(5).offset(10).many();

Locking

  • lockForUpdate, forShare
await sql.query("users").lockForUpdate().many();
await sql.query("users").forShare().many();

CTEs (Common Table Expressions)

  • with
await sql
.query("users")
.with("normal", (cte) => cte.newCte("users_cte", (b) => b.select("name")))
.many();

Copying & Query Output

  • copy, toQuery, unWrap
const qb = sql.query("users").where("isActive", true);
const qbCopy = qb.copy();
const sqlString = qb.toQuery();

QueryBuilder Only

  • All methods are available on QueryBuilder, but no model/relation helpers.

Next: Relations