Fluent Builder

Build queries programmatically with the fluent API for dynamic query construction.

When to Use

Use the fluent builder when you need to construct queries dynamically based on runtime conditions. For static queries, prefer the cook template literal.

SELECT Builder

select.ts
import { select } from 'genaql';

const query = select('users')
  .columns('id', 'name', 'email')
  .where('active', '=', true)
  .where('role', 'in', ['admin', 'moderator'])
  .orderBy('created_at', 'desc')
  .limit(10)
  .offset(20);

const { sql, params } = query.toParams();

Dynamic Conditions

dynamic.ts
// Build query based on filters
function searchUsers(filters: UserFilters) {
  let query = select('users').columns('*');

  if (filters.name) {
    query = query.where('name', 'like', `%${filters.name}%`);
  }

  if (filters.role) {
    query = query.where('role', '=', filters.role);
  }

  if (filters.minAge) {
    query = query.where('age', '>=', filters.minAge);
  }

  if (filters.sortBy) {
    query = query.orderBy(filters.sortBy, filters.sortDir || 'asc');
  }

  return query.limit(filters.limit || 20);
}

INSERT Builder

insert.ts
import { insert } from 'genaql';

// Single row
const query = insert('users')
  .columns('name', 'email')
  .values(['John', 'john@test.com'])
  .returning('id');

// Multiple rows
const bulkQuery = insert('users')
  .columns('name', 'email')
  .values([
    ['John', 'john@test.com'],
    ['Jane', 'jane@test.com'],
    ['Bob', 'bob@test.com']
  ])
  .returning('id');

// With conflict handling (upsert)
const upsertQuery = insert('users')
  .columns('email', 'name')
  .values(['john@test.com', 'John'])
  .onConflict('email')
  .doUpdate({ name: 'John Updated' })
  .returning('*');

UPDATE Builder

update.ts
import { update } from 'genaql';

const query = update('users')
  .set({ status: 'active', verified: true })
  .where('id', '=', 1)
  .returning('*');

// Increment/decrement
const incrementQuery = update('posts')
  .set({ views: raw('views + 1') })
  .where('id', '=', 42);

DELETE Builder

delete.ts
import { deleteFrom } from 'genaql';

const query = deleteFrom('users')
  .where('id', '=', 1)
  .returning('id', 'email');

// Delete with multiple conditions
const bulkDelete = deleteFrom('sessions')
  .where('expired', '=', true)
  .orWhere('created_at', '<', '2024-01-01');

Builder Methods

MethodDescription
.columns(...cols)Specify columns to select/insert
.where(col, op, val)Add AND condition
.orWhere(col, op, val)Add OR condition
.whereIn(col, vals)Add IN condition
.whereNull(col)Add IS NULL condition
.join(table, on)Add INNER JOIN
.leftJoin(table, on)Add LEFT JOIN
.orderBy(col, dir)Add ORDER BY
.groupBy(...cols)Add GROUP BY
.having(col, op, val)Add HAVING
.limit(n)Add LIMIT
.offset(n)Add OFFSET
.returning(...cols)Add RETURNING

Immutability

All builder methods return a new query object, leaving the original unchanged. This makes it safe to create variations from a base query.