Skip to content
API/QueryBuilder

QueryBuilder

src/services/query-builder.ts37 public methodsclass

Fluent, capability-checked builder for one driver’s query URIs.

Every mutator writes to the QubeeStore it was given and returns this, so a whole query is one chain; generateUri() turns the current state into a URI through the driver’s request strategy. A method the driver cannot express throws at the call site instead of emitting a parameter the backend would ignore.

new QueryBuilder(store: QubeeStore, requestStrategy: IRequestStrategy, options: QueryBuilderOptions, driver?: DriverId)
Parameter Type Description
store QubeeStore State container holding the query being built
requestStrategy IRequestStrategy Driver strategy that turns state into a URI
options QueryBuilderOptions Query parameter key names for the active driver
driver DriverId Active driver id, used to name it in capability errors; any string, so a custom driver can pass its own
addEmbedded(relation: string, ...columns: string[]): this

Add an embedded resource to the select statement (PostgREST only)

Splices relation(col1,col2) into the single select= query parameter alongside flat columns from addSelect. Omit the columns to project all of them (relation(*)):

qb.addEmbedded('author', 'id', 'name')
.addEmbedded('comments')
.addSelect('title');
// → select=title,author(id,name),comments(*)

Calling repeatedly with the same relation merge-dedups the columns. Does not reset the page (column shape change, not record-set change).

Parameter Type Description
relation string The related table / foreign-key name as PostgREST sees it
columns string[] Optional column projection; omit for relation(*)
addFields(model: string, fields: string[]): this

Add fields to the select statement for the given model (JSON:API and Spatie only)

Parameter Type Description
model string Model that holds the fields
fields string[] Fields to select
addFilter(field: string, ...values: (string | number | boolean)[]): this

Add a filter with the given value(s) (JSON:API, NestJS, PostgREST, and Spatie)

Produces: filter[field]=value (JSON:API / Spatie) or filter.field=value (NestJS)

Parameter Type Description
field string Name of the field to filter
values (string | number | boolean)[] The needle(s)
addFilterOperator(field: string, operator: FilterOperatorEnum, ...values: (string | number | boolean)[]): this

Add a filter with an explicit operator (NestJS and PostgREST)

Produces: filter.field=$operator:value

Parameter Type Description
field string Name of the field to filter
operator FilterOperatorEnum The filter operator to apply
values (string | number | boolean)[] The value(s) for the filter
addIncludes(...models: string[]): this

Add related entities to include in the request (JSON:API and Spatie only)

Parameter Type Description
models string[] Models to include
addSelect(...fields: string[]): this

Add flat field selection (NestJS and PostgREST)

Produces: select=col1,col2

Parameter Type Description
fields string[] Fields to select
addSort(field: string, order: SortEnum): this

Add a field with a sort criteria (JSON:API, NestJS, PostgREST, and Spatie)

Parameter Type Description
field string Field to use for sorting
order SortEnum A value from the SortEnum enumeration
currentPage(): number

Get the current page number

Returns — The current page number

deleteEmbedded(...relations: string[]): this

Remove embedded resources from the current query builder state (PostgREST only)

Removes the whole relation entry, columns included.

Parameter Type Description
relations string[] Relation names to remove
deleteFields(fields: Fields): this

Delete selected fields for the given models in the current query builder state (JSON:API and Spatie only)

builder.deleteFields({
users: ['email', 'password'],
address: ['zipcode']
});
Parameter Type Description
fields Fields Object mapping model names to field arrays to remove
deleteFieldsByModel(model: string, ...fields: string[]): this

Delete selected fields for the given model in the current query builder state (JSON:API and Spatie only)

builder.deleteFieldsByModel('users', 'email', 'password');
Parameter Type Description
model string Model that holds the fields
fields string[] Fields to delete from the state
deleteFilters(...filters: string[]): this

Remove given filters from the query builder state (JSON:API, NestJS, PostgREST, and Spatie)

Parameter Type Description
filters string[] Filters to remove
deleteIncludes(...includes: string[]): this

Remove selected related models from the query builder state (JSON:API and Spatie only)

Parameter Type Description
includes string[] Models to remove
deleteOperatorFilters(...fields: string[]): this

Remove operator filters by field name (NestJS and PostgREST)

Parameter Type Description
fields string[] Field names of operator filters to remove
deleteParams(...keys: string[]): this

Remove extra query parameters set with setParam() (all drivers)

Resets the page to 1, as removing a filter does. Calling it with no keys is a no-op.

Parameter Type Description
keys string[] Parameter keys to remove
deleteSearch(): this

Remove search term from the query builder state (NestJS only)

deleteSelect(...fields: string[]): this

Remove flat field selections from the query builder state (NestJS and PostgREST)

Parameter Type Description
fields string[] Fields to remove from selection
deleteSorts(...sorts: string[]): this

Remove sort rules from the query builder state (JSON:API, NestJS, PostgREST, and Spatie)

Parameter Type Description
sorts string[] Fields used for sorting to remove
firstPage(): this

Navigate to the first page (page 1)

generateUri(): string

Build the URI for the current state using the active driver.

Synchronous: URI construction performs no I/O. ng-qubee wrapped this in an Observable purely for Angular ergonomics, and converted the throw below into a stream error; adapters can re-wrap it however their framework prefers. Subscribe to the store to be told when the result would change.

Parameters set with setParam() are appended once the request strategy has returned, after the driver’s own, so every strategy emits them.

Returns — The generated URI

goToPage(n: number): this

Navigate directly to the specified page

Validates integer/positive via the existing setPage path, and additionally rejects values that exceed state.lastPage when pagination bounds are known.

Parameter Type Description
n number Target page number
hasNextPage(): boolean

Check whether a next page exists

Returns — true if state.page < state.lastPage when bounds are known, or true when bounds are unknown

hasPreviousPage(): boolean

Check whether a previous page exists

Returns — true if state.page > 1

isFirstPage(): boolean

Check whether the current page is the first page

Returns — true if state.page === 1

isLastPage(): boolean

Check whether the current page is the last page

Returns — true only when state.isLastPageKnown and state.page === state.lastPage

lastPage(): this

Navigate to the last page known from the most recent paginated response

nextPage(): this

Navigate to the next page

paginationHeaders(): Record<string, string> | null

HTTP request headers the active driver wants the consumer to apply

Returns null for drivers that pass all pagination metadata on the URL (Laravel, Spatie, JSON:API, NestJS, and PostgREST in its default QUERY mode). Returns a map of header name → value when the active driver uses HTTP headers instead — today, only the PostgREST driver configured with PaginationModeEnum.RANGE, which yields { 'Range-Unit': 'items', 'Range': 'from-to' }.

Returns — Map of headers to apply to the HTTP request, or null when not needed

previousPage(): this

Navigate to the previous page

reset(): this

Clear the current state and reset the Query Builder to a fresh, clean condition

setBaseUrl(baseUrl: string): this

Set the base URL to use for composing the address

Trailing slashes are dropped when the URI is joined, so https://api.dev/ and https://api.dev both produce https://api.dev/articles. The state keeps the value as given.

Parameter Type Description
baseUrl string The base URL
setLimit(limit: number): this

Set the items per page number

Validation is delegated to the active request strategy because the accepted range is driver-specific: nestjs-paginate additionally accepts -1 as a “fetch all” sentinel, while Laravel, Spatie, and JSON:API require a positive integer.

Parameter Type Description
limit number Number of items per page (or -1 to fetch all, NestJS only)
setPage(page: number): this

Set the page that the backend will use to paginate the result set

Parameter Type Description
page number Page number
setParam(key: string, ...values: (string | number | boolean)[]): this

Set a query parameter no driver models (all drivers)

For what a backend accepts beyond the driver’s own parameters — a top-level status, an include on a driver without includes. It is appended by generateUri() after the driver’s parameters, so it works with every driver, custom ones included, and is not gated by capabilities. Params come out in the order their keys were first set, except that integer-like keys such as '2024' come first, as they do in any JavaScript object.

The key is emitted verbatim, so bracketed names such as meta[tag] work — and so a key must never be built from end-user input. Each value is percent-encoded the way filter values are, then the values are joined with a literal , — so a comma inside a value arrives as %2C:

qb.setParam('status', 'failed'); // → status=failed
qb.setParam('ids', 'a,b', 'c'); // → ids=a%2Cb,c

A key is emitted once: repeated keys (id=1&id=2) are not supported. Setting a key again replaces its values. Calling it with no values is a no-op; remove a key with deleteParams(). Resets the page to 1, as adding a filter does.

A key must not collide with a parameter the driver emits: generateUri() throws ParamCollisionError rather than duplicate or override it.

Parameter Type Description
key string The parameter name, emitted verbatim
values (string | number | boolean)[] The value(s)
setResource(resource: string): this

Set the API resource to run the query against

A path works too: projects/42/tasks produces /projects/42/tasks. Leading slashes are dropped when the URI is joined, so the URI never starts with //; a trailing slash is kept, for backends whose routes end in one. The resource is not encoded: encode any path segment that comes from data — `projects/${encodeURIComponent(id)}/tasks`.

On JSON:API and Spatie, a nested resource names no type the path can tell (users/42/followers returns users), so addFields() keys go out as given, unchecked.

Parameter Type Description
resource string Resource name or path (e.g. ‘users’ produces /users)
setSearch(search: string): this

Set the search term for full-text search (NestJS only)

Produces: search=term

Parameter Type Description
search string The search term
totalPages(): number

Get the total number of pages reported by the most recent paginated response

Returns — The last page number