Query Builder API
Every fluent method on NgQubeeService. All methods that mutate state return this for chaining; capability methods return values without mutating.
Driver compatibility is gated at runtime — calling an unsupported method throws an Unsupported*Error. The per-driver pages list which methods each driver accepts.
State setup
setResource(name)
Required before any URI generation. Becomes the first path segment.
qb.setResource('users'); // → /users…
Triggers an auto-reset of page.
setBaseUrl(url)
Optional. Prepends a base URL (e.g. https://api.example.com) to every generated URI.
qb.setBaseUrl('https://api.example.com'); // → https://api.example.com/users…
Does not trigger auto-reset (URL prefix only).
setLimit(n) / setPage(n)
Pagination position.
qb.setLimit(25).setPage(2); // 25 items, page 2
setLimit triggers auto-reset of page. setPage of course does not. NestJS additionally accepts setLimit(-1) as the fetch-all sentinel. Spring emits page 0-indexed on the wire — your state stays 1-indexed.
Filters
addFilter(field, ...values) / deleteFilters(...fields)
Simple key-value filters. Multi-value calls merge per field.
qb.addFilter('status', 'active'); // single
qb.addFilter('id', 1, 2, 3); // multi-value
qb.deleteFilters('status'); // remove
Spatie / JSON:API: filter[status]=active. NestJS: filter.status=active. PostgREST: status=eq.active (single) or status=in.(1,2,3) (multi). Strapi: filters[status][$eq]=active. DRF: status=active (single) or status__in=1,2,3 (multi). @nestjsx/crud: filter=status||$eq||active (single) or filter=status||$in||1,2,3 (multi). Sieve: filters=status==active (single) or filters=status==1|2|3 (multi). OData: $filter=status eq 'active' (single) or $filter=status in (1,2,3) (multi). Directus: filter[status][_eq]=active (single) or filter[status][_in]=1,2,3 (multi). json-server: status=active (single) or status:in=1,2,3 (multi). API Platform: status=active (single) or status[]=a&status[]=b (multi); relation dot paths (author.name=John) pass through. Feathers: status=active (single) or status[$in][0]=active&status[$in][1]=pending (multi). PocketBase: filter=(status='active') (single) or filter=((status='active' || status='pending')) (multi). Payload: where[status][equals]=active (single) or where[status][in]=active,pending (multi). WordPress: status=publish (single) or categories=2,3 (multi, CSV).
Triggers auto-reset.
addFilterOperator(field, operator, ...values) / deleteOperatorFilters(...fields)
Filters with explicit comparison operators. Supported by API Platform, Directus, Feathers, json-server, NestJS, @nestjsx/crud, OData, Payload, PocketBase, PostgREST, Sieve, Strapi, and DRF.
import { FilterOperatorEnum } from 'ng-qubee';
qb.addFilterOperator('age', FilterOperatorEnum.GTE, 18);
qb.addFilterOperator('id', FilterOperatorEnum.IN, 1, 2, 3);
The full operator list: EQ, NOT, NULL, IN, GT, GTE, LT, LTE, BTW, ILIKE, SW, CONTAINS. PostgREST adds FTS, PLFTS, PHFTS, WFTS. Per-driver support varies — DRF and API Platform reject NOT (no generic negation filter) plus the FTS family (PostgREST-only); Strapi, @nestjsx/crud, Sieve, OData, Directus, and PocketBase reject only the FTS family; json-server additionally rejects ILIKE (no case-insensitive variant) and NULL (no null-check operator); Feathers rejects CONTAINS/ILIKE/SW (LIKE-style matching is adapter-specific, not part of the common syntax) and NULL on top of the FTS family; Payload rejects SW (no starts-with operator) plus the FTS family. See each driver's page for detailed mappings: API Platform, Directus, Feathers, json-server, NestJS, @nestjsx/crud, OData, Payload, PocketBase, PostgREST, Sieve, Strapi, DRF.
Triggers auto-reset.
Sorting
addSort(field, order) / deleteSorts(...fields)
import { SortEnum } from 'ng-qubee';
qb.addSort('created_at', SortEnum.DESC);
qb.addSort('name', SortEnum.ASC);
qb.deleteSorts('created_at');
Spatie / JSON:API: sort=-created_at,name. NestJS: sortBy=created_at:DESC,name:ASC. PostgREST: order=created_at.desc,name.asc. Strapi: sort[0]=created_at:desc&sort[1]=name:asc. DRF: ordering=-created_at,name. @nestjsx/crud: sort=created_at,DESC&sort=name,ASC. Spring: sort=created_at,desc&sort=name,asc. Sieve: sorts=-created_at,name. OData: $orderby=created_at desc,name asc. Directus: sort=-created_at,name. json-server: _sort=-created_at,name. API Platform: order[created_at]=desc&order[name]=asc. Feathers: $sort[created_at]=-1&$sort[name]=1. PocketBase: sort=-created_at,name. Payload: sort=-created_at,name. WordPress: orderby=created_at&order=desc (single sort only — the first rule wins).
Triggers auto-reset.
Column selection
addSelect(...fields) / deleteSelect(...fields) — Directus / Feathers / NestJS / @nestjsx/crud / OData / Payload / PocketBase / PostgREST / Strapi / WordPress
Flat column list:
qb.addSelect('id', 'email', 'name'); // select=id,email,name
Does not trigger auto-reset (column shape change, not record-set change).
addFields(model, fields) / deleteFields({ model: [...] }) / deleteFieldsByModel(model, ...fields) — JSON:API / Spatie
Per-model selection:
qb.addFields('users', ['id', 'email']); // fields[users]=id,email
qb.deleteFields({ users: ['email'] });
qb.deleteFieldsByModel('users', 'email');
Does not trigger auto-reset.
Includes — JSON:API / Spatie / Strapi / @nestjsx/crud / OData / Directus / PocketBase / WordPress
addIncludes(...models) / deleteIncludes(...models)
qb.addIncludes('profile', 'posts'); // include=profile,posts
qb.deleteIncludes('profile');
Does not trigger auto-reset (related-resource shape, not record set).
Embedded resources — PostgREST / OData / Directus
addEmbedded(relation, ...columns) / deleteEmbedded(...relations)
PostgREST's idiomatic join mechanism: related-table columns are spliced into the single select= query parameter, alongside any flat columns from addSelect.
qb.addEmbedded('author', 'id', 'name') // author(id,name)
.addEmbedded('comments') // comments(*) — no columns = all columns
.addSelect('title');
// → select=title,author(id,name),comments(*)
qb.deleteEmbedded('comments'); // removes the whole relation entry
With embedded relations but no addSelect, the flat part defaults to * so the base row's columns stay in the projection. Repeated calls for the same relation merge-dedup the columns. On OData, embedded relations emit as $expand=rel($select=col1,col2) inline projections instead; on Directus, as rel.col dot paths inside the fields= CSV. Every other driver throws UnsupportedEmbeddedError — drivers with a standalone relation parameter expose it through addIncludes instead.
Does not trigger auto-reset (column shape change, not record set).
Search — NestJS / DRF / OData / Directus / json-server / WordPress
setSearch(term) / deleteSearch()
qb.setSearch('john doe'); // search=john doe
qb.deleteSearch();
Triggers auto-reset.
Auto-reset of page
Several mutations reset state.page to 1 automatically because they invalidate the current page position:
setLimit(page count changes)setResource(different record set)setSearch/deleteSearch(different record set)addFilter/deleteFilters(different record set)addFilterOperator/deleteOperatorFilters(different record set)addSort/deleteSorts(different ordering)
Methods that change record shape (addFields, addIncludes, addSelect, setBaseUrl) leave page untouched.
Lifecycle
generateUri()
Returns an Observable<string> that emits the composed URI:
qb.generateUri().subscribe(uri => /* … */);
URIs do not auto-emit on state mutations — call generateUri() explicitly when you want the next URI.
reset()
Resets state to defaults (clears all filters, sorts, fields, includes, sets page=1, limit=15):
qb.reset();
Pagination navigation
See Pagination for nextPage, previousPage, firstPage, lastPage, goToPage, currentPage, totalPages, isFirstPage, isLastPage, hasNextPage, hasPreviousPage, paginationHeaders.