Skip to main content

QQueryBuilder

@quik/database


@quik/database / QQueryBuilder

Class: QQueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:94

Builder class for creating SQL queries based on find options.

This class provides a fluent interface for building complex SQL queries with support for:

  1. Joining related tables based on entity relationships
  2. Building complex where clauses with various operators and conditions
  3. Adding sorting, pagination, and other query modifiers
  4. Converting between entity properties and database column names

Example​

// Basic query with conditions
const query = QQueryBuilder.build(
{ where: { status: 'active' } },
userEntity
);

// Advanced query with relations and sorting
const query = QQueryBuilder.build(
{
where: { status: 'active' },
relations: ['profile', 'orders'],
sort: [{ field: 'createdAt', direction: 'desc' }],
limit: 10
},
userEntity,
knexInstance
);

// Execute the query
const results = await query;

See​

QRepository For higher-level database operations using this builder

Extends​

  • QObject

Type Parameters​

TModel​

TModel extends QModel = QModel

Constructors​

Constructor​

new QQueryBuilder<TModel>(findOptions, entity, queryBuilder?): QQueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:117

Creates a new query builder.

Parameters​

findOptions​

QFindOptions<TModel>

Options for the find operation

entity​

TModel

The entity model being queried

queryBuilder?​

QueryBuilder<TModel>

Optional existing query builder to extend

Returns​

QQueryBuilder<TModel>

Overrides​

QObject.constructor

Accessors​

entity​

Get Signature​

get protected entity(): TModel

Defined in: database/src/repository/QQueryBuilder.ts:149

Gets the entity model being queried.

Returns​

TModel


findOptions​

Get Signature​

get protected findOptions(): QFindOptions<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:156

Gets the find options.

Returns​

QFindOptions<TModel>


logger​

Get Signature​

get protected logger(): IQLogger

Defined in: core/src/QObject.ts:15

The logger getter for the object.

Returns​

IQLogger

Inherited from​

QObject.logger


name​

Get Signature​

get name(): string

Defined in: core/src/QObject.ts:8

Returns​

string

Inherited from​

QObject.name


queryBuilder​

Get Signature​

get protected queryBuilder(): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:133

Gets the underlying query builder.

Returns​

QueryBuilder<TModel>

Set Signature​

set protected queryBuilder(value): void

Defined in: database/src/repository/QQueryBuilder.ts:142

Sets the underlying query builder.

Parameters​
value​

QueryBuilder<TModel>

New query builder

Returns​

void

Methods​

applyCountAggregate()​

protected applyCountAggregate(countDefinition, alias): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:471

Applies the count aggregate to the current query builder.

Parameters​

countDefinition​

QCountAggregateOption<TModel>

Count configuration

alias​

string

Alias for the aggregate column

Returns​

QueryBuilder<TModel>


buildGroupedCountQuery()​

protected buildGroupedCountQuery(findOptions): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:380

Builds a grouped count query and automatically groups by selected fields.

Parameters​

findOptions​

QGroupedCountOptions<TModel>

Grouped count options

Returns​

QueryBuilder<TModel>


buildGroupedSelectExpression()​

protected buildGroupedSelectExpression(selectOption): object

Defined in: database/src/repository/QQueryBuilder.ts:433

Resolves a grouped select definition into SQL select and group-by expressions.

Parameters​

selectOption​

QGroupSelectOption<TModel>

Grouped select definition

Returns​

object

alias​

alias: string

groupBy​

groupBy: string | Raw<any>

select​

select: string | Raw<any>


buildQuery()​

protected buildQuery(): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:344

Builds the complete query based on find options.

This method orchestrates the query building process by:

  1. Setting up column mappings between entity properties and database fields
  2. Adding relation joins if specified in find options
  3. Applying where conditions for filtering
  4. Adding sorting directives
  5. Applying pagination (limit/offset) if specified
  6. Handling count queries if requested

The query is built in a specific order to ensure correct SQL generation:

  • First, column mappings are created for the base entity
  • Next, relation joins are added (if specified)
  • Then, where conditions are applied
  • Followed by sorting directives
  • Finally, pagination and count options are applied

Returns​

QueryBuilder<TModel>

Throws​

Error If relation specified doesn't exist on the model

Example​

// Create a query builder with complete options
const builder = new QQueryBuilder(
{
where: { isActive: true },
relations: ['profile'],
sort: [{ field: 'createdAt', direction: 'desc' }],
limit: 10,
offset: 20
},
userEntity
);

// Build and execute the query
const query = builder.buildQuery();
const results = await query;

// Count query example
const countBuilder = new QQueryBuilder(
{
where: { isActive: true },
count: true
},
userEntity
);

const countResult = await countBuilder.buildQuery();
console.log('Total count:', countResult[0].count);

See​


buildRelation()​

protected buildRelation(relation, model, modelRelations, prefix?, levelRelations?, relations?, select?): void

Defined in: database/src/repository/QQueryBuilder.ts:643

Builds a single relation join.

This method creates SQL join clauses for a specific relation by:

  1. Validating that the relation exists on the model
  2. Resolving the related entity class
  3. Creating appropriate table aliases for the join
  4. Adding columns from the related table to the query
  5. Creating the appropriate join clause based on relation type (one-to-many, many-to-many)
  6. Recursively processing nested relations if specified

Parameters​

relation​

string

Relation name to build

model​

TModel

Parent model

modelRelations​

string[]

Available relations on the model

prefix?​

string

Optional prefix for table aliases

levelRelations?​

string[] = []

Relations at the current level

relations?​

QFindRelations

Optional nested relations

select?​

string[]

Optional nested relation selects

Returns​

void

Throws​

Error If the specified relation doesn't exist on the model

Throws​

Error If the relation entity cannot be resolved

Example​

// Build a single relation join for 'profile' relation
builder.buildRelation(
'profile',
userModel,
['profile', 'orders'],
undefined,
[]
);
// This creates a join between users and profiles tables

See​

  • buildRelations For handling multiple relations
  • EntityStore For entity class resolution

buildRelations()​

protected buildRelations(model, relations, prefix?): void

Defined in: database/src/repository/QQueryBuilder.ts:566

Builds relation joins for a model.

This method handles the complex task of joining related tables by:

  1. Identifying the relations defined on the model
  2. Processing both simple string relations and complex nested relation objects
  3. Creating appropriate SQL joins with proper table aliases
  4. Recursively handling nested relations

Relations can be specified in multiple formats:

  • Simple string format: ['profile', 'orders']
  • Nested relation format: [{ 'orders': ['items', 'payments'] }]
  • Mixed format: ['profile', { 'orders': ['items'] }]

Parameters​

model​

TModel

Model to build relations for

relations​

QFindRelations

Relations to include

prefix?​

string

Optional prefix for table aliases

Returns​

void

Throws​

Error If a specified relation doesn't exist on the model

Example​

// Build simple relations for a user model
builder.buildRelations(
userModel,
['profile', 'orders']
);
// This creates joins for profile and orders

// Build nested relations
builder.buildRelations(
userModel,
['profile', { 'orders': ['items', 'payments'] }]
);
// This creates joins for profile, orders, order items, and order payments

// Multiple levels of nesting
builder.buildRelations(
userModel,
[{ 'orders': [{ 'items': ['product'] }] }]
);
// This creates joins from user to orders to items to products

See​


buildSortClause()​

protected buildSortClause(): void

Defined in: database/src/repository/QQueryBuilder.ts:1054

Builds sort clauses based on find options.

This method adds ORDER BY clauses to the query by:

  1. Iterating through all sort conditions in the find options
  2. Adding each field and direction to the query builder
  3. Supporting multiple sort fields with different directions

Sort options are specified as an array of objects, each with:

  • field: The field name to sort by
  • direction: Optional sort direction ('asc' or 'desc', defaults to 'asc')

The order of sort conditions in the array determines their precedence in the SQL ORDER BY clause.

Returns​

void

Example​

// Sort by a single field ascending (default)
builder.findOptions = {
sort: [{ field: 'name' }]
};
builder.buildSortClause();
// Produces: ORDER BY name ASC

// Sort by a single field descending
builder.findOptions = {
sort: [{ field: 'createdAt', direction: 'desc' }]
};
builder.buildSortClause();
// Produces: ORDER BY createdAt DESC

// Sort by multiple fields with different directions
builder.findOptions = {
sort: [
{ field: 'status', direction: 'asc' },
{ field: 'createdAt', direction: 'desc' },
{ field: 'name', direction: 'asc' }
]
};
builder.buildSortClause();
// Produces: ORDER BY status ASC, createdAt DESC, name ASC

See​


buildWhereClause()​

protected buildWhereClause(): void

Defined in: database/src/repository/QQueryBuilder.ts:781

Builds where clauses based on find options.

This method handles the complexity of SQL where conditions by:

  1. Detecting the type of where condition (array, builder, single condition, or object)
  2. Delegating to the appropriate handler method based on condition type
  3. Applying the conditions to the query builder

The method supports various condition formats:

  • Arrays of conditions (combined with AND)
  • QWhereBuilder instances for complex nested conditions
  • Single condition objects with field, operator, and value
  • Plain objects for simple equality conditions

Returns​

void

Example​

// Simple object where clause (field equality)
builder.findOptions = { where: { status: 'active', role: 'user' } };
builder.buildWhereClause();
// Produces: WHERE status = 'active' AND role = 'user'

// Array of condition objects
builder.findOptions = {
where: [
{ field: 'status', operator: 'eq', value: 'active' },
{ field: 'createdAt', operator: 'gt', value: '2023-01-01' }
]
};
builder.buildWhereClause();
// Produces: WHERE status = 'active' AND createdAt > '2023-01-01'

// Single condition object
builder.findOptions = {
where: { field: 'email', operator: 'like', value: '%@example.com' }
};
builder.buildWhereClause();
// Produces: WHERE email LIKE '%@example.com'

// Complex where clause with QWhereBuilder
const whereBuilder = QWhereBuilder.New()
.Equal('status', 'active')
.Or(
QWhereBuilder.New()
.Equal('role', 'admin')
.Equal('department', 'IT')
);

builder.findOptions = { where: whereBuilder };
builder.buildWhereClause();
// Produces: WHERE status = 'active' OR (role = 'admin' AND department = 'IT')

See​


convertOperator()​

protected convertOperator(operator): QWhereOperator

Defined in: database/src/repository/QQueryBuilder.ts:514

Converts string-based operators to symbol-based operators.

This utility method translates human-readable operator strings into their SQL symbol equivalents for use in database queries. It handles:

  • Comparison operators like 'lt', 'gt', 'eq'
  • Falling back to the original operator if no conversion exists

The string-based operators provide a more readable alternative in code:

  • 'lt' for less than (<)
  • 'lte' for less than or equal (<=)
  • 'gt' for greater than (>)
  • 'gte' for greater than or equal (>=)
  • 'eq' for equals (=)
  • 'ne' for not equals (<>)

Parameters​

operator​

QWhereComparisonOperatorString

Operator to convert

Returns​

QWhereOperator

Example​

// Convert string operators to symbols
const ltSymbol = builder.convertOperator('lt'); // Returns '<'
const gteSymbol = builder.convertOperator('gte'); // Returns '>='
const eqSymbol = builder.convertOperator('eq'); // Returns '='

// Operator without conversion is returned as-is
const likeOp = builder.convertOperator('like'); // Returns 'like'
const inOp = builder.convertOperator('in'); // Returns 'in'

See​


endSpan()​

protected endSpan(span): void

Defined in: core/src/QObject.ts:35

End a span returned by startSpan.

Parameters​

span​

TelemetrySpan

The span to end.

Returns​

void

Inherited from​

QObject.endSpan


initializeColumns()​

protected initializeColumns(): void

Defined in: database/src/repository/QQueryBuilder.ts:418

Initializes the field-to-column mapping for the base entity.

Returns​

void


normalizeRelationValue()​

protected normalizeRelationValue(value?): object

Defined in: database/src/repository/QQueryBuilder.ts:588

Normalizes a relation declaration into explicit nested relations and selected fields.

Parameters​

value?​

QRelationValue

Relation configuration value

Returns​

object

relations?​

optional relations?: QFindRelations

select?​

optional select?: string[]


recordSpanError()​

protected recordSpanError(span, err): void

Defined in: core/src/QObject.ts:45

Record an exception on an active span.

Parameters​

span​

TelemetrySpan

The span to record the error on.

err​

unknown

The error to record.

Returns​

void

Inherited from​

QObject.recordSpanError


resolveWhereField()​

protected resolveWhereField(field): string

Defined in: database/src/repository/QQueryBuilder.ts:816

Parameters​

field​

string

Returns​

string


setSpanAttribute()​

protected setSpanAttribute(span, key, value): void

Defined in: core/src/QObject.ts:64

Set a single attribute on an active span.

Parameters​

span​

TelemetrySpan

The span to update.

key​

string

Attribute key.

value​

string | number | boolean

Attribute value.

Returns​

void

Inherited from​

QObject.setSpanAttribute


startSpan()​

protected startSpan(spanName, options?): TelemetrySpan

Defined in: core/src/QObject.ts:26

Start a telemetry span for the given operation name. Returns undefined when no telemetry provider is active.

Parameters​

spanName​

string

Name of the span.

options?​

TelemetrySpanOptions

Optional span attributes and kind.

Returns​

TelemetrySpan

Inherited from​

QObject.startSpan


transformWhereBuilder()​

protected transformWhereBuilder(queryBuilder, whereBuilder, clause?): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:975

Transforms a where builder into a Knex query clause.

This method handles complex nested where conditions by:

  1. Iterating through all conditions in the where builder
  2. Determining the appropriate logical operator (AND/OR) between conditions
  3. Handling both simple conditions and nested condition groups
  4. Recursively processing nested where builders
  5. Building a complete where clause structure with proper nesting

Parameters​

queryBuilder​

QueryBuilder<TModel>

Query builder to modify

whereBuilder​

QWhereBuilder

Where builder containing conditions to apply

clause?​

"where" | "having"

Returns​

QueryBuilder<TModel>

Example​

// Create a complex where builder with nested conditions
const whereBuilder = new QWhereBuilder()
.Equal('status', 'active')
.Or(
new QWhereBuilder()
.Equal('role', 'admin')
.Equal('department', 'IT')
);

// Transform it into a Knex query
const query = builder.transformWhereBuilder(knexQuery, whereBuilder);
// Produces: WHERE status = 'active' OR (role = 'admin' AND department = 'IT')

See​


transformWhereCondition()​

protected transformWhereCondition(queryBuilder, whereCondition, linker?, clause?): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:894

Transforms a where condition into a Knex query clause.

This method converts abstract condition objects into SQL where clauses by:

  1. Determining the appropriate SQL function to call based on the condition type
  2. Handling special operators like 'is null', 'like', 'in', and 'between'
  3. Converting string-based operators to their symbol equivalents
  4. Applying negation if specified in the condition
  5. Properly formatting field names and values for the database

Special operators are handled differently:

  • 'is null': Uses special SQL syntax
  • 'like': Used for pattern matching with % wildcards
  • 'in': Checks if value is in a list of options
  • 'between': Checks if value is within a range

Parameters​

queryBuilder​

QueryBuilder<TModel>

Query builder to modify

whereCondition​

QWhereCondition

Condition to apply

linker?​

"or" | "and"

Optional logical operator to link with previous conditions

clause?​

"where" | "having"

Returns​

QueryBuilder<TModel>

Throws​

Error If an invalid operator is used (will default to '=')

Example​

// Transform a simple equality condition
const newBuilder = builder.transformWhereCondition(
knexQuery,
{ field: 'status', operator: '=', value: 'active' }
);
// Produces: WHERE status = 'active'

// Transform a string operator condition
const newBuilder = builder.transformWhereCondition(
knexQuery,
{ field: 'age', operator: 'gte', value: 18 }
);
// Produces: WHERE age >= 18

// Special operator: 'is null'
const newBuilder = builder.transformWhereCondition(
knexQuery,
{ field: 'deletedAt', operator: 'is null' }
);
// Produces: WHERE deletedAt IS NULL

// Special operator: 'in' with array
const newBuilder = builder.transformWhereCondition(
knexQuery,
{ field: 'status', operator: 'in', value: ['active', 'pending'] }
);
// Produces: WHERE status IN ('active', 'pending')

// Negated condition with 'and' linker
const newBuilder = builder.transformWhereCondition(
knexQuery,
{ field: 'role', operator: 'in', value: ['admin', 'moderator'], isNegated: true },
'and'
);
// Produces: AND role NOT IN ('admin', 'moderator')

See​

  • convertOperator For converting string operators to symbols
  • OPERATOR_NEGATION For handling negated conditions
  • QWhereCondition For the structure of condition objects

applyHaving()​

static applyHaving<TModel>(queryBuilder, havingBuilder, entity): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:253

Applies a QWhereBuilder's conditions as a HAVING clause, using the same field resolution and operator handling as applyWhere. Typically used after a GROUP BY to filter on aggregate results.

Type Parameters​

TModel​

TModel extends QModel

Parameters​

queryBuilder​

QueryBuilder<TModel>

Query builder to apply the conditions onto.

havingBuilder​

QWhereBuilder

Conditions to apply.

entity​

TModel

Entity used to resolve unqualified field names; only its entityName is used.

Returns​

QueryBuilder<TModel>


applyWhere()​

static applyWhere<TModel>(queryBuilder, whereBuilder, entity): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:236

Applies a QWhereBuilder's conditions directly onto an existing Knex query builder, without any of build()'s other side effects (relation joins, soft-delete filtering, forced column selection).

Field names should be fully qualified as table.column (e.g. ProjectTeam.projectId) when the query spans more than one table, such as with a manually joined query — unqualified field names fall back to entity's own table. This is the mechanism QJoinQueryBuilder uses to support .where() on arbitrary joins.

Type Parameters​

TModel​

TModel extends QModel

Parameters​

queryBuilder​

QueryBuilder<TModel>

Query builder to apply the conditions onto.

whereBuilder​

QWhereBuilder

Conditions to apply.

entity​

TModel

Entity used to resolve unqualified field names; only its entityName is used.

Returns​

QueryBuilder<TModel>

Example​

const query = QQueryBuilder.applyWhere(
knex('ProjectTeamMember').join('ProjectTeam', 'ProjectTeam.id', 'ProjectTeamMember.projectTeamId'),
QWhereBuilder.New().Equal('ProjectTeam.projectId', projectId),
new ProjectTeamMember()
);

build()​

static build<TModel>(findOptions, entity, queryBuilder?): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:206

Static factory method to build a query.

This method simplifies query creation by:

  1. Creating a new query builder instance
  2. Applying all find options (where, relations, sort, etc.)
  3. Returning the fully configured Knex query builder

Type Parameters​

TModel​

TModel extends QModel

Parameters​

findOptions​

QFindOptions<TModel>

Options for filtering, relations, sorting, and pagination

entity​

TModel

The entity model being queried

queryBuilder?​

QueryBuilder<TModel>

Optional existing query builder to extend

Returns​

QueryBuilder<TModel>

Throws​

Error If relation specified doesn't exist on the model

Example​

// Simple query to find active users
const query = QQueryBuilder.build(
{ where: { status: 'active' } },
new UserModel()
);

// Query with complex where condition using QWhereBuilder
const whereBuilder = QWhereBuilder.New()
.Equal('status', 'active')
.And(QWhereBuilder.New().GreaterThan('lastLogin', '2023-01-01'));

const query = QQueryBuilder.build(
{ where: whereBuilder },
new UserModel()
);

// Query with relations and extending existing builder
const query = QQueryBuilder.build(
{ relations: ['profile', 'orders'] },
new UserModel(),
knex('users').where('isDeleted', false)
);

// Execute the query
const users = await query;

See​


buildGroupedCount()​

static buildGroupedCount<TModel>(findOptions, entity, queryBuilder?): QueryBuilder<TModel>

Defined in: database/src/repository/QQueryBuilder.ts:269

Builds a grouped count query with automatic group-by clauses for selected fields.

Type Parameters​

TModel​

TModel extends QModel

Parameters​

findOptions​

QGroupedCountOptions<TModel>

Grouped count options

entity​

TModel

The entity model being queried

queryBuilder?​

QueryBuilder<TModel>

Optional existing query builder to extend

Returns​

QueryBuilder<TModel>