QueryBuilder
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.
Constructor
Section titled “Constructor”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 |
Methods
Section titled “Methods”addEmbedded()
Section titled “addEmbedded()”addEmbedded(relation: string, ...columns: string[]): thisAdd 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()
Section titled “addFields()”addFields(model: string, fields: string[]): thisAdd 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()
Section titled “addFilter()”addFilter(field: string, ...values: (string | number | boolean)[]): thisAdd 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()
Section titled “addFilterOperator()”addFilterOperator(field: string, operator: FilterOperatorEnum, ...values: (string | number | boolean)[]): thisAdd 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()
Section titled “addIncludes()”addIncludes(...models: string[]): thisAdd related entities to include in the request (JSON:API and Spatie only)
| Parameter | Type | Description |
|---|---|---|
models |
string[] |
Models to include |
addSelect()
Section titled “addSelect()”addSelect(...fields: string[]): thisAdd flat field selection (NestJS and PostgREST)
Produces: select=col1,col2
| Parameter | Type | Description |
|---|---|---|
fields |
string[] |
Fields to select |
addSort()
Section titled “addSort()”addSort(field: string, order: SortEnum): thisAdd 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()
Section titled “currentPage()”currentPage(): numberGet the current page number
Returns — The current page number
deleteEmbedded()
Section titled “deleteEmbedded()”deleteEmbedded(...relations: string[]): thisRemove 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()
Section titled “deleteFields()”deleteFields(fields: Fields): thisDelete 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()
Section titled “deleteFieldsByModel()”deleteFieldsByModel(model: string, ...fields: string[]): thisDelete 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()
Section titled “deleteFilters()”deleteFilters(...filters: string[]): thisRemove given filters from the query builder state (JSON:API, NestJS, PostgREST, and Spatie)
| Parameter | Type | Description |
|---|---|---|
filters |
string[] |
Filters to remove |
deleteIncludes()
Section titled “deleteIncludes()”deleteIncludes(...includes: string[]): thisRemove selected related models from the query builder state (JSON:API and Spatie only)
| Parameter | Type | Description |
|---|---|---|
includes |
string[] |
Models to remove |
deleteOperatorFilters()
Section titled “deleteOperatorFilters()”deleteOperatorFilters(...fields: string[]): thisRemove operator filters by field name (NestJS and PostgREST)
| Parameter | Type | Description |
|---|---|---|
fields |
string[] |
Field names of operator filters to remove |
deleteParams()
Section titled “deleteParams()”deleteParams(...keys: string[]): thisRemove 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()
Section titled “deleteSearch()”deleteSearch(): thisRemove search term from the query builder state (NestJS only)
deleteSelect()
Section titled “deleteSelect()”deleteSelect(...fields: string[]): thisRemove flat field selections from the query builder state (NestJS and PostgREST)
| Parameter | Type | Description |
|---|---|---|
fields |
string[] |
Fields to remove from selection |
deleteSorts()
Section titled “deleteSorts()”deleteSorts(...sorts: string[]): thisRemove 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()
Section titled “firstPage()”firstPage(): thisNavigate to the first page (page 1)
generateUri()
Section titled “generateUri()”generateUri(): stringBuild 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()
Section titled “goToPage()”goToPage(n: number): thisNavigate 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()
Section titled “hasNextPage()”hasNextPage(): booleanCheck whether a next page exists
Returns — true if state.page < state.lastPage when bounds are known, or true when bounds are unknown
hasPreviousPage()
Section titled “hasPreviousPage()”hasPreviousPage(): booleanCheck whether a previous page exists
Returns — true if state.page > 1
isFirstPage()
Section titled “isFirstPage()”isFirstPage(): booleanCheck whether the current page is the first page
Returns — true if state.page === 1
isLastPage()
Section titled “isLastPage()”isLastPage(): booleanCheck whether the current page is the last page
Returns — true only when state.isLastPageKnown and state.page === state.lastPage
lastPage()
Section titled “lastPage()”lastPage(): thisNavigate to the last page known from the most recent paginated response
nextPage()
Section titled “nextPage()”nextPage(): thisNavigate to the next page
paginationHeaders()
Section titled “paginationHeaders()”paginationHeaders(): Record<string, string> | nullHTTP 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()
Section titled “previousPage()”previousPage(): thisNavigate to the previous page
reset()
Section titled “reset()”reset(): thisClear the current state and reset the Query Builder to a fresh, clean condition
setBaseUrl()
Section titled “setBaseUrl()”setBaseUrl(baseUrl: string): thisSet 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()
Section titled “setLimit()”setLimit(limit: number): thisSet 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()
Section titled “setPage()”setPage(page: number): thisSet the page that the backend will use to paginate the result set
| Parameter | Type | Description |
|---|---|---|
page |
number |
Page number |
setParam()
Section titled “setParam()”setParam(key: string, ...values: (string | number | boolean)[]): thisSet 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=failedqb.setParam('ids', 'a,b', 'c'); // → ids=a%2Cb,cA 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()
Section titled “setResource()”setResource(resource: string): thisSet 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()
Section titled “setSearch()”setSearch(search: string): thisSet the search term for full-text search (NestJS only)
Produces: search=term
| Parameter | Type | Description |
|---|---|---|
search |
string |
The search term |
totalPages()
Section titled “totalPages()”totalPages(): numberGet the total number of pages reported by the most recent paginated response
Returns — The last page number
