Query Builder Deep Dive
Master the fluent query builder with joins, subqueries, CTEs, unions, and aggregations
Select & Filtering
examples/select-filter.ts
// Select specific columnsconst users = await userRepo.find().select("id", "name", "email").execute(orm.client);
// Select with aliasconst results = await userRepo.find().as("u").select("u.name").execute(orm.client);
// Distinct valuesconst distinctNames = await userRepo.find().distinct().select("name").execute(orm.client);
// Where conditionsconst active = await userRepo.find() .where("isActive = ?", true) .where("age >= ?", 18) .execute(orm.client);
// OR conditionsconst admins = await userRepo.find() .where("role = ?", "admin") .orWhere("role = ?", "superadmin") .execute(orm.client);
// IN / NOT INconst selected = await userRepo.find() .whereIn("id", [1, 2, 3, 4]) .execute(orm.client);
// BETWEENconst ageRange = await userRepo.find() .whereBetween("age", 18, 35) .execute(orm.client);
// LIKE / ILIKEconst searchResults = await userRepo.find() .whereLike("name", "%john%") .execute(orm.client);
// NULL checksconst noEmail = await userRepo.find() .whereNull("email") .execute(orm.client);Joins
examples/joins.ts
// Inner joinconst results = await userRepo.find() .innerJoin("posts", "users.id = posts.userId") .select("users.name", "posts.title") .execute(orm.client);
// Left join with aggregationconst userPostCounts = await userRepo.find() .leftJoin("posts", "users.id = posts.userId") .select("users.name", "COUNT(posts.id) as postCount") .groupBy("users.id", "users.name") .execute(orm.client);
// Multiple joinsconst fullData = await orderRepo.find() .innerJoin("customers", "orders.customerId = customers.id") .innerJoin("order_items", "orders.id = order_items.orderId") .innerJoin("products", "order_items.productId = products.id") .select("customers.name", "products.name as product", "order_items.quantity") .execute(orm.client);
// Cross joinconst combinations = await colorRepo.find() .crossJoin("sizes") .select("colors.name", "sizes.label") .execute(orm.client);Aggregations
examples/aggregations.ts
// Countconst total = await userRepo.find().count("*").execute(orm.client);
// Sum, Avg, Min, Maxconst stats = await productRepo.find() .select("SUM(price) as total", "AVG(price) as average", "MIN(price) as lowest", "MAX(price) as highest") .execute(orm.client);
// Group by with havingconst categoryStats = await productRepo.find() .select("categoryId", "COUNT(*) as productCount", "AVG(price) as avgPrice") .groupBy("categoryId") .having("COUNT(*) > ?", 5) .execute(orm.client);Subqueries & EXISTS
examples/subqueries.ts
// WHERE EXISTSconst usersWithPosts = await userRepo.find() .whereExists( "SELECT 1 FROM posts WHERE posts.userId = users.id" ) .execute(orm.client);
// WHERE NOT EXISTSconst usersWithoutPosts = await userRepo.find() .whereNotExists( "SELECT 1 FROM posts WHERE posts.userId = users.id" ) .execute(orm.client);
// Subquery in WHEREconst activeAuthors = await userRepo.find() .whereIn("id", postRepo.find().select("authorId").build().query ) .execute(orm.client);Common Table Expressions (CTEs)
examples/ctes.ts
// WITH clauseconst qb = new QueryBuilder("orders");const cte = new QueryBuilder("recent_orders") .select("*") .where("createdAt > ?", "2025-01-01");
const results = await qb .with("recent_orders", cte) .select("*") .join("recent_orders", "orders.id = recent_orders.id") .execute(orm.client);
// Recursive CTE (for hierarchical data)const hierarchy = new QueryBuilder("categories");const anchor = new QueryBuilder("categories") .select("*") .where("parentId IS NULL");const recursive = new QueryBuilder("categories") .select("categories.*") .join("category_tree", "categories.parentId = category_tree.id");
const tree = await hierarchy .withRecursive("category_tree", anchor) .select("*") .execute(orm.client);Unions & Locking
examples/unions-locks.ts
// UNIONconst allNames = await userRepo.find() .select("name") .union(adminRepo.find().select("name")) .execute(orm.client);
// UNION ALLconst combined = await activeUsersQB .unionAll(inactiveUsersQB) .execute(orm.client);
// SELECT FOR UPDATE (pessimistic locking)const lockedUser = await userRepo.find() .where("id = ?", 1) .forUpdate() .execute(orm.client);
// SELECT FOR SHAREconst sharedData = await productRepo.find() .where("id = ?", productId) .forShare() .execute(orm.client);
// Paginationconst page = await userRepo.find() .orderBy("createdAt", "DESC") .paginate(1, 20) .execute(orm.client);