/** * Fluent SQL query builder for `@atlex/orm`. * * Provides an opinionated, chainable API over a private Knex instance, without * exposing Knex types in the public surface. */ import type { Knex } from 'knex'; import { type Connection } from './Connection.js'; import { CursorPaginator } from './pagination/CursorPaginator.js'; import { LengthAwarePaginator } from './pagination/LengthAwarePaginator.js'; import type { CursorPaginationOptions, PaginationOptions } from './pagination/PaginationMeta.js'; import { Paginator } from './pagination/Paginator.js'; type Direction = 'asc' | 'desc'; interface CompiledSQL { sql: string; bindings: unknown[]; } /** * Opaque raw SQL expression usable inside `select`, `whereRaw`, etc. * This is an Atlex wrapper around a Knex raw expression. */ export declare class RawExpression { private readonly native; /** @internal */ constructor(native: Knex.Raw); /** @internal */ _native(): Knex.Raw; } type ColumnExpression = string | RawExpression; export declare class QueryBuilder> { private readonly connection; private state; /** * Create a new QueryBuilder. * * @param connection - Connection to build queries against. */ constructor(connection: Connection); /** * Clone the current builder. The clone is independent and can be mutated * without affecting the original builder instance. * * @returns A deep copy of this builder. * @example * const base = db('users').where('active', true) * const admins = base.clone().where('role', 'admin') */ clone(): QueryBuilder; /** * Run all subsequent queries on an existing Knex transaction (used by test helpers). * * @param trx - Open transaction. * @returns This builder (fluent). */ withTransaction(trx: Knex.Transaction): this; /** * Execute a callback within a database transaction. * * @param callback - Callback executed inside a transaction. * @returns The callback result. * @example * await db('users').transaction(async (trx) => trx.where('id', 1).lockForUpdate().first()) */ transaction(callback: (qb: QueryBuilder) => Promise): Promise; /** * @internal Configure a row mapper for terminal read methods. */ _mapRow(mapper: (row: Record) => TNext): QueryBuilder; /** * @internal Configure an after-fetch hook used for eager loading. */ _afterFetch(callback: (rows: TResult[]) => Promise): this; /** * Create a raw SQL expression with optional bindings. * * @param sql - Raw SQL fragment. * @param bindings - Optional bindings for placeholders. * @returns An opaque raw expression usable in this query builder. * @example * db('users').select(db('users').raw('COUNT(*) as total')).first() */ raw(sql: string, bindings?: readonly unknown[]): RawExpression; /** * Set the target table for the query (supports `table as alias` syntax). * * @param name - Table name. * @returns this * @example * db().table('users as u') */ table(name: string): this; /** * Select specific columns (defaults to `*` when no columns are selected). * * @param columns - Column names (or raw expressions). * @returns this * @example * db('users').select('id', 'email') */ select(...columns: ColumnExpression[]): this; /** * Add DISTINCT to the select query. * * @returns this * @example * db('users').distinct().pluck('email') */ distinct(): this; /** * Append columns to the existing select list. * * @param columns - Columns to append. * @returns this * @example * db('users').select('id').addSelect('email') */ addSelect(...columns: ColumnExpression[]): this; /** * Add a WHERE clause. * * @param column - Column name. * @param operatorOrValue - Operator (e.g. `=`, `>`) or the value (shorthand). * @param value - Value for the condition. * @returns this * @example * db('users').where('age', '>=', 18) */ where(column: string, operator: string, value: unknown): this; where(column: string, value: unknown): this; where(callback: (qb: QueryBuilder) => void): this; /** * Add an OR WHERE clause. * * @param column - Column name. * @param operatorOrValue - Operator or value (shorthand). * @param value - Value for the condition. * @returns this * @example * db('users').where('role', 'admin').orWhere('role', 'owner') */ orWhere(column: string, operator: string, value: unknown): this; orWhere(column: string, value: unknown): this; orWhere(callback: (qb: QueryBuilder) => void): this; /** * Add a negated WHERE clause. * * @param column - Column name. * @param operatorOrValue - Operator or value (shorthand). * @param value - Value for the condition. * @returns this * @example * db('users').whereNot('status', 'disabled') */ whereNot(column: string, operator: string, value: unknown): this; whereNot(column: string, value: unknown): this; /** * Add a WHERE IN clause. * * @param column - Column name. * @param values - Values list. * @returns this * @example * db('users').whereIn('id', [1,2,3]) */ whereIn(column: string, values: readonly unknown[]): this; /** * Add a WHERE NOT IN clause. * * @param column - Column name. * @param values - Values list. * @returns this * @example * db('users').whereNotIn('status', ['disabled', 'banned']) */ whereNotIn(column: string, values: readonly unknown[]): this; /** * Add a WHERE NULL clause. * * @param column - Column name. * @returns this * @example * db('users').whereNull('deleted_at') */ whereNull(column: string): this; /** * Add a WHERE NOT NULL clause. * * @param column - Column name. * @returns this * @example * db('users').whereNotNull('email_verified_at') */ whereNotNull(column: string): this; /** * Add a WHERE BETWEEN clause. * * @param column - Column name. * @param range - Inclusive range tuple. * @returns this * @example * db('orders').whereBetween('total', [10, 100]) */ whereBetween(column: string, range: readonly [unknown, unknown]): this; /** * Add a WHERE NOT BETWEEN clause. * * @param column - Column name. * @param range - Inclusive range tuple. * @returns this * @example * db('orders').whereNotBetween('total', [10, 100]) */ whereNotBetween(column: string, range: readonly [unknown, unknown]): this; /** * Add a WHERE EXISTS subquery. * * @param callback - Callback that builds the subquery. * @returns this * @example * db('users').whereExists(q => q.table('posts').whereRaw('posts.user_id = users.id')) */ whereExists(callback: (qb: QueryBuilder) => void): this; /** * Add a raw WHERE clause with optional bindings. * * @param sql - SQL fragment. * @param bindings - Bindings for placeholders. * @returns this * @example * db('users').whereRaw('email like ?', ['%@example.com']) */ whereRaw(sql: string, bindings?: readonly unknown[]): this; /** * Order the results by a column. * * @param column - Column name. * @param direction - Sort direction. * @returns this * @example * db('users').orderBy('id', 'desc') */ orderBy(column: string, direction?: Direction): this; /** * Order using a raw SQL expression. * * @param sql - Raw ORDER BY clause. * @returns this * @example * db('users').orderByRaw('FIELD(role, "owner", "admin", "user")') */ orderByRaw(sql: string): this; /** * Remove all `ORDER BY` clauses (offset and cursor pagination helpers). * * @returns this */ clearOrder(): this; /** * Order by a column descending (default `created_at`). * * @param column - Column name. * @returns this * @example * db('posts').latest() */ latest(column?: string): this; /** * Order by a column ascending (default `created_at`). * * @param column - Column name. * @returns this * @example * db('posts').oldest() */ oldest(column?: string): this; /** * Group results by one or more columns. * * @param columns - Columns to group by. * @returns this * @example * db('orders').groupBy('user_id') */ groupBy(...columns: string[]): this; /** * Add a HAVING clause. * * @param column - Column name. * @param operator - Operator. * @param value - Value. * @returns this * @example * db('orders').groupBy('user_id').having('total', '>', 100) */ having(column: string, operator: string, value: unknown): this; /** * Add a raw HAVING clause with optional bindings. * * @param sql - Raw SQL. * @param bindings - Bindings. * @returns this * @example * db('orders').groupBy('user_id').havingRaw('SUM(total) > ?', [100]) */ havingRaw(sql: string, bindings?: readonly unknown[]): this; /** * Limit the number of returned rows. * * @param n - Max rows. * @returns this * @example * db('users').limit(10) */ limit(n: number): this; /** * Offset the returned rows. * * @param n - Offset. * @returns this * @example * db('users').offset(20) */ offset(n: number): this; /** * Apply limit/offset for a page. * * @param page - 1-based page number. * @param perPage - Items per page (default 15). * @returns this * @example * db('users').forPage(2, 25) */ forPage(page: number, perPage?: number): this; /** * Inner join another table. * * @param table - Table to join. * @param first - Left side column. * @param operator - Join operator. * @param second - Right side column. * @returns this * @example * db('users').join('posts', 'posts.user_id', '=', 'users.id') */ join(table: string, first: string, operator: string, second: string): this; /** * Left join another table. * * @param table - Table to join. * @param first - Left side column. * @param operator - Join operator. * @param second - Right side column. * @returns this * @example * db('users').leftJoin('posts', 'posts.user_id', '=', 'users.id') */ leftJoin(table: string, first: string, operator: string, second: string): this; /** * Right join another table. * * @param table - Table to join. * @param first - Left side column. * @param operator - Join operator. * @param second - Right side column. * @returns this * @example * db('users').rightJoin('posts', 'posts.user_id', '=', 'users.id') */ rightJoin(table: string, first: string, operator: string, second: string): this; /** * Cross join another table. * * @param table - Table to cross join. * @returns this * @example * db('a').crossJoin('b') */ crossJoin(table: string): this; /** * Join using raw SQL. * * @param sql - Raw join SQL. * @param bindings - Bindings for placeholders. * @returns this * @example * db('users').joinRaw('join roles on roles.id = users.role_id') */ joinRaw(sql: string, bindings?: readonly unknown[]): this; /** * Lock selected rows for update (SELECT ... FOR UPDATE). * * @returns this * @example * await db('users').where('id', 1).lockForUpdate().first() */ lockForUpdate(): this; /** * Acquire a shared lock (FOR SHARE / LOCK IN SHARE MODE depending on driver). * * @returns this * @example * await db('users').where('id', 1).sharedLock().first() */ sharedLock(): this; /** * Run a side-effect callback against this builder without breaking the chain. * * @param callback - Callback to run. * @returns this * @example * db('users').tap(q => console.log(q.toSQL())) */ tap(callback: (qb: this) => void): this; /** * Conditionally apply a scope callback. * * @param condition - Condition to evaluate. * @param callback - Scope to apply when condition is true. * @param fallback - Optional scope to apply when condition is false. * @returns this * @example * db('users').when(isAdmin, q => q.where('role', 'admin')) */ when(condition: boolean, callback: (qb: this) => void, fallback?: (qb: this) => void): this; /** * Apply a scope unless a condition is true. * * @param condition - Condition to negate. * @param callback - Scope to apply when condition is false. * @returns this * @example * db('users').unless(includeDisabled, q => q.whereNull('disabled_at')) */ unless(condition: boolean, callback: (qb: this) => void): this; /** * Compile SQL without executing (useful for debugging). * * @returns SQL + bindings. * @example * const { sql, bindings } = db('users').where('id', 1).toSQL() */ toSQL(): CompiledSQL; /** * Dump the compiled SQL and continue the chain. * * @returns this * @example * db('users').where('id', 1).dump().first() */ dump(): this; /** * Dump the compiled SQL and abort execution. * * @throws Always throws after logging. * @example * db('users').where('id', 1).dd() */ dd(): never; /** * Fetch all matching rows. * * @returns Matching rows. * @example * const rows = await db('users').get<{ id: number }>() */ get(): Promise; /** * Fetch the first matching row or null. * * @returns First matching row or null. * @example * const user = await db('users').where('id', 1).first() */ first(): Promise; /** * Fetch the first matching row or throw `NotFoundException`. * * @returns First matching row. * @throws NotFoundException * @example * const user = await db('users').where('email', 'a@b.com').firstOrFail() */ firstOrFail(): Promise; /** * Find a row by primary key (default `id`). * * @param id - Primary key value. * @returns The found row or null. * @example * const user = await db('users').find(1) */ find(id: number | string): Promise; /** * Find a row by primary key or throw `NotFoundException`. * * @param id - Primary key value. * @returns The found row. * @throws NotFoundException * @example * const user = await db('users').findOrFail(1) */ findOrFail(id: number | string): Promise; /** * Return a single column as a flat array. * * @param column - Column name. * @returns Array of values from the column. * @example * const ids = await db('users').pluck('id') */ pluck(column: string): Promise; /** * Return the first row's column value. * * @param column - Column name. * @returns The value or null. * @example * const email = await db('users').where('id', 1).value('email') */ value(column: string): Promise; /** * Count matching rows. * * @param column - Column to count (default `*`). * @returns Count. * @example * const total = await db('users').count() */ count(column?: string): Promise; /** * Get the maximum value of a column. * * @param column - Column name. * @returns Maximum value (0 when no rows). * @example * const maxId = await db('users').max('id') */ max(column: string): Promise; /** * Get the minimum value of a column. * * @param column - Column name. * @returns Minimum value (0 when no rows). * @example * const minId = await db('users').min('id') */ min(column: string): Promise; /** * Get the average value of a column. * * @param column - Column name. * @returns Average value (0 when no rows). * @example * const avgAge = await db('users').avg('age') */ avg(column: string): Promise; /** * Get the sum of a column. * * @param column - Column name. * @returns Sum (0 when no rows). * @example * const revenue = await db('orders').sum('total') */ sum(column: string): Promise; /** * Check whether any records match. * * @returns True when at least one record exists. * @example * const hasUsers = await db('users').exists() */ exists(): Promise; /** * Check whether no records match. * * @returns True when no records exist. * @example * const empty = await db('users').doesntExist() */ doesntExist(): Promise; /** * Insert a record or records. * * For a single object, returns the inserted id. * For an array (bulk insert), returns affected row count. * * @param data - Record or records to insert. * @returns Inserted id (single) or row count (bulk). * @example * const id = await db('users').insert({ email: 'a@b.com' }) */ insert(data: Record | Record[]): Promise; /** * Insert a record and return the new id across pg/mysql/sqlite. * * @param data - Record to insert. * @returns Inserted id. * @example * const id = await db('users').insertGetId({ email: 'a@b.com' }) */ insertGetId(data: Record): Promise; /** * Update matching rows. * * @param data - Partial update data. * @returns Number of affected rows. * @example * const updated = await db('users').where('id', 1).update({ name: 'New' }) */ update(data: Record): Promise; /** * Update a record matching `search`, or insert if none exists. * * @param search - Search criteria. * @param data - Data to update/insert. * @returns void * @example * await db('settings').updateOrInsert({ key: 'site_name' }, { value: 'Atlex' }) */ updateOrInsert(search: Record, data: Record): Promise; /** * Increment a numeric column. * * @param column - Column name. * @param amount - Amount (default 1). * @returns Number of affected rows. * @example * await db('users').where('id', 1).increment('login_count') */ increment(column: string, amount?: number): Promise; /** * Decrement a numeric column. * * @param column - Column name. * @param amount - Amount (default 1). * @returns Number of affected rows. * @example * await db('users').where('id', 1).decrement('credits', 5) */ decrement(column: string, amount?: number): Promise; /** * Delete matching rows. * * @returns Number of deleted rows. * @example * const deleted = await db('sessions').where('user_id', 1).delete() */ delete(): Promise; /** * Truncate the table. * * @returns void * @example * await db('logs').truncate() */ truncate(): Promise; /** * Paginate with total count (COUNT + paged SELECT). * * @param perPage - Items per page (default {@link LengthAwarePaginator.defaultPerPage}). * @param options.page - 1-based page (default from resolver or `1`). * @example * const p = await db('users').where('active', true).paginate(15, { page: 2 }) */ paginate(perPage?: number, options?: PaginationOptions): Promise>; /** * Simple pagination: one query with `LIMIT perPage + 1` (no COUNT). */ simplePaginate(perPage?: number, options?: PaginationOptions): Promise>; /** * Cursor (keyset) pagination using the current `orderBy` columns, or `primaryKeyColumn` / `id`. */ cursorPaginate(perPage?: number, options?: CursorPaginationOptions): Promise>; private applySearch; /** @internal */ private applyWheres; /** @internal */ private buildQuery; private execute; private executeCount; private executeAggregate; } export {}; //# sourceMappingURL=QueryBuilder.d.ts.map