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 equalgt,gte,lt,lte: Comparisonlike,notLike: Pattern matchingin,notIn: Array membershipisNull,isNotNull: Null checks
Parameters:
column: Column nameoperator: Comparison operatorvalue: 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 optionscache: Cache configuration overridequeryId: 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 joinleftColumn: Column from current tablerightColumn: 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 sumalias: 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 columninterval: 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 bydirection:'ASC'or'DESC'
having()
Filter aggregated results:
db.table('orders')
.select(['country'])
.sum('amount', 'revenue')
.groupBy(['country'])
.having('revenue > 100000')
Parameters:
condition: SQL condition stringparameters(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 orfalseto 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 columninterval: 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 columnalias: 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:
- Building Queries - Learn query patterns
- Serve API Reference - serve framework API