Thanks to visit codestin.com
Credit goes to hypequery.com

Query Builder API Reference

Complete API reference for all query builder methods. Works identically in both serve framework and standalone usage.

Core Methods

table()

Start a query from a table:

db.table('users')

Parameters:

  • tableName: Name of the table (must exist in schema)

Returns: QueryBuilder instance

select()

Specify which columns to return:

// Select specific columns
db.table('users').select(['id', 'name', 'email'])

// Select all columns
db.table('users').select('*')

// Select with aliases
db.table('users').select(['id', 'name AS user_name'])

// Select from joined tables
db.table('orders')
  .innerJoin('users', 'user_id', 'users.id')
  .select(['orders.id', 'users.name', 'orders.amount'])

Parameters:

  • columns: Array of column names or '*' for all columns

Returns: QueryBuilder instance with updated output type

where()

Filter rows based on conditions:

// Simple condition
db.table('users').where('status', 'eq', 'active')

// Multiple conditions (AND)
db.table('users')
  .where('status', 'eq', 'active')
  .where('age', 'gte', 18)

// Conditional where (null/undefined is ignored)
db.table('users')
  .where(input.status ? ['status', 'eq', input.status] : null)

Operators:

  • eq, neq: Equal, not equal
  • gt, gte, lt, lte: Comparison
  • like, notLike: Pattern matching
  • in, notIn: Array membership
  • isNull, isNotNull: Null checks

Parameters:

  • column: Column name
  • operator: Comparison operator
  • value: Value to compare against

Returns: QueryBuilder instance

See Filtering for more details.

execute()

Execute the query and return results:

const results = await db
  .table('users')
  .where('status', 'eq', 'active')
  .select(['id', 'name'])
  .execute();

Parameters:

  • options (optional): Execution options
    • cache: Cache configuration override
    • queryId: Custom query ID for logging

Returns: Promise of typed result array

stream()

Execute query and stream results:

const stream = await db
  .table('orders')
  .select(['id', 'amount'])
  .stream();

const reader = stream.getReader();
while (true) {
  const { done, value: rows } = await reader.read();
  if (done) break;
  console.log(rows);
}

Returns: Promise of ReadableStream

streamForEach()

Stream results with callback:

await db
  .table('events')
  .select(['id', 'event_type'])
  .streamForEach(async (row) => {
    await processEvent(row);
  });

Parameters:

  • callback: Function called for each row batch

Returns: Promise that resolves when stream completes

Joins

innerJoin()

Perform an inner join:

db.table('orders')
  .innerJoin('users', 'user_id', 'users.id')
  .select(['orders.id', 'users.name'])

Parameters:

  • table: Table to join
  • leftColumn: Column from current table
  • rightColumn: Column from joined table (format: 'table.column')
  • alias (optional): Alias for joined table

leftJoin()

Perform a left join:

db.table('orders')
  .leftJoin('users', 'user_id', 'users.id')
  .select(['orders.id', 'users.name'])

rightJoin()

Perform a right join:

db.table('users')
  .rightJoin('orders', 'id', 'orders.user_id')

fullJoin()

Perform a full outer join:

db.table('users')
  .fullJoin('orders', 'id', 'orders.user_id')

withRelation()

Use predefined relationships:

// First define relationships
const relationships = new JoinRelationships<Schema>();
relationships.define('userOrders', {
  from: 'orders',
  to: 'users',
  leftColumn: 'user_id',
  rightColumn: 'id',
  type: 'LEFT'
});

QueryBuilder.setJoinRelationships(relationships);

// Then use in queries
db.table('orders')
  .withRelation('userOrders')
  .select(['orders.id', 'users.name'])

See Joins and Join Relationships for more details.

Aggregations

sum()

Calculate sum of a column:

db.table('orders')
  .sum('amount', 'total_revenue')

Parameters:

  • column: Column to sum
  • alias: Alias for the result

count()

Count rows or non-null values:

db.table('users')
  .count('id', 'user_count')

avg()

Calculate average:

db.table('orders')
  .avg('amount', 'avg_order_value')

min()

Find minimum value:

db.table('orders')
  .min('amount', 'min_order')

max()

Find maximum value:

db.table('orders')
  .max('amount', 'max_order')

See Aggregations for more details.

Grouping & Ordering

groupBy()

Group results:

db.table('orders')
  .select(['country'])
  .sum('amount', 'revenue')
  .groupBy(['country'])

Parameters:

  • columns: Array of columns to group by

groupByTimeInterval()

Group by time intervals:

// Built-in intervals
db.table('events')
  .count('id', 'event_count')
  .groupByTimeInterval('created_at', null, 'toStartOfHour')

// Custom intervals
db.table('events')
  .count('id', 'event_count')
  .groupByTimeInterval('created_at', '5 minute')

Parameters:

  • column: Timestamp column
  • interval: Custom interval string (e.g., ‘5 minute’, ‘1 hour’)
  • function: Built-in ClickHouse function (e.g., ‘toStartOfHour’)

See Time Functions for more details.

orderBy()

Sort results:

db.table('users')
  .orderBy('created_at', 'DESC')

// Multiple sorts
db.table('users')
  .orderBy('country', 'ASC')
  .orderBy('created_at', 'DESC')

Parameters:

  • column: Column to sort by
  • direction: 'ASC' or 'DESC'

having()

Filter aggregated results:

db.table('orders')
  .select(['country'])
  .sum('amount', 'revenue')
  .groupBy(['country'])
  .having('revenue > 100000')

Parameters:

  • condition: SQL condition string
  • parameters (optional): Parameter values

Limiting & Pagination

limit()

Limit number of results:

db.table('users').limit(10)

Parameters:

  • count: Maximum number of rows to return

offset()

Skip rows:

db.table('users')
  .orderBy('created_at', 'DESC')
  .limit(20)
  .offset(40) // Page 3 (skip first 40)

Parameters:

  • count: Number of rows to skip

distinct()

Return only unique rows:

db.table('orders')
  .select(['country'])
  .distinct()

Utility Methods

toSQL()

Get generated SQL string:

const query = db
  .table('users')
  .where('status', 'eq', 'active')
  .select(['id', 'name']);

const sql = query.toSQL();
// SELECT id, name FROM users WHERE status = 'active'

Returns: SQL string with parameters interpolated

toSQLWithParams()

Get SQL and parameters separately:

const { sql, parameters } = db
  .table('orders')
  .where('amount', 'gt', 1000)
  .toSQLWithParams();

console.log(sql);        // SELECT * FROM orders WHERE amount > ?
console.log(parameters); // [1000]

Returns: Object with sql string and parameters array

debug()

Print query information:

db.table('users')
  .where('status', 'eq', 'active')
  .debug() // Logs SQL, parameters, settings
  .execute();

Returns: QueryBuilder instance (chainable)

getConfig()

Access current query configuration:

const config = db
  .table('users')
  .select(['id'])
  .getConfig();

console.log(config);
// { table: 'users', select: ['id'], where: [], ... }

Returns: Query configuration object

raw()

Insert raw SQL fragments:

db.table('events')
  .raw('WHERE date BETWEEN toStartOfMonth(now()) AND now()')
  .execute();

Parameters:

  • sql: Raw SQL string

Returns: QueryBuilder instance

Warning: Raw SQL bypasses type safety. Use sparingly.

settings()

Configure ClickHouse query settings:

db.table('large_table')
  .settings({
    max_execution_time: 30,
    max_memory_usage: '10000000000',
    max_threads: 4,
  })
  .execute();

Parameters:

  • settings: ClickHouse settings object

Returns: QueryBuilder instance

cache()

Configure query caching:

db.table('users')
  .where('status', 'eq', 'active')
  .cache({
    mode: 'cache-first',
    ttlMs: 60000, // 1 minute
    tags: ['users'],
  })
  .execute();

Parameters:

  • options: Cache configuration or false to disable

Returns: QueryBuilder instance

See Caching for more details.

Time Functions

toStartOfInterval()

Convert timestamp to interval start:

db.table('events')
  .select([
    'id',
    toStartOfInterval('created_at', '1 hour', 'hour_bucket'),
  ])
  .groupBy(['hour_bucket'])

Parameters:

  • column: Timestamp column
  • interval: Interval string (e.g., ‘1 hour’, ‘5 minute’)
  • alias: Alias for the result

datePart()

Extract date component:

db.table('events')
  .select([
    datePart('year', 'created_at', 'year'),
    datePart('month', 'created_at', 'month'),
    datePart('day', 'created_at', 'day'),
  ])

Parameters:

  • part: Date component (‘year’, ‘month’, ‘day’, ‘hour’, etc.)
  • column: Timestamp column
  • alias: Alias for the result

See Time Functions for complete reference.

Type Safety

All methods maintain full TypeScript type safety:

interface Schema {
  users: {
    id: 'Int32';
    name: 'String';
    age: 'UInt8';
    created_at: 'DateTime';
  };
  orders: {
    id: 'Int32';
    user_id: 'Int32';
    amount: 'Decimal64(2)';
    status: 'String';
  };
}

const db = createQueryBuilder<Schema>();

// ✅ Type-safe
const users = await db
  .table('users')
  .where('age', 'gte', 18)
  .select(['id', 'name'])
  .execute();
// users: Array<{ id: number; name: string }>

// ❌ TypeScript errors
db.table('users')
  .where('invalid_column', 'eq', 'value') // Error: column doesn't exist
  .select(['id', 'invalid']) // Error: column doesn't exist
  .sum('name', 'total'); // Error: can't sum string column

Next Steps

Continue: Connection Options - Configure ClickHouse connection

Or explore: