PostgREST / Supabase Driver
Targets PostgREST and anything built on it — most notably Supabase.
Configure
import { DriverEnum, provideNgQubee } from 'ng-qubee';
bootstrapApplication(AppComponent, {
providers: [provideNgQubee({ driver: DriverEnum.POSTGREST })]
});
Wire format
| Concern | Output |
|---|---|
| Filters (single value) | col=eq.value |
| Filters (multi-value) | col=in.(v1,v2,v3) |
| Operator filters | full FilterOperatorEnum mapping — see below |
| Sort | order=col1.asc,col2.desc |
| Flat select | select=col1,col2 |
| Pagination | limit=15&offset=0 (offset omitted on page 1) |
Operator filters
Every FilterOperatorEnum value maps to PostgREST's prefix syntax:
import { FilterOperatorEnum } from 'ng-qubee';
qb.addFilterOperator('age', FilterOperatorEnum.GTE, 18); // age=gte.18
qb.addFilterOperator('id', FilterOperatorEnum.IN, 1, 2, 3); // id=in.(1,2,3)
qb.addFilterOperator('status', FilterOperatorEnum.NOT, 'deleted'); // status=not.eq.deleted
qb.addFilterOperator('id', FilterOperatorEnum.NOT, 1, 2); // id=not.in.(1,2)
qb.addFilterOperator('deletedAt', FilterOperatorEnum.NULL, true); // deletedAt=is.null
qb.addFilterOperator('deletedAt', FilterOperatorEnum.NULL, false); // deletedAt=is.not.null
qb.addFilterOperator('price', FilterOperatorEnum.BTW, 10, 100); // price=gte.10&price=lte.100
qb.addFilterOperator('email', FilterOperatorEnum.SW, 'admin'); // email=like.admin*
qb.addFilterOperator('name', FilterOperatorEnum.CONTAINS, 'john'); // name=ilike.%john%
Value shape rules
Enforced at call time — both throw InvalidFilterOperatorValueError:
BTWrequires exactly 2 values ([min, max]).NULLrequires exactly 1 boolean value (true→IS NULL,false→IS NOT NULL).
Other operators leave shape validation to the server.
Full-text search
Four PostgREST-native variants:
qb.addFilterOperator('description', FilterOperatorEnum.FTS, 'rat'); // description=fts.rat
qb.addFilterOperator('description', FilterOperatorEnum.PLFTS, 'a b'); // description=plfts.a b
qb.addFilterOperator('description', FilterOperatorEnum.PHFTS, 'a b'); // description=phfts.a b
qb.addFilterOperator('description', FilterOperatorEnum.WFTS, 'a -b'); // description=wfts.a -b
| Operator | SQL function | Meaning |
|---|---|---|
FTS | to_tsquery | Raw tsquery syntax (advanced) |
PLFTS | plainto_tsquery | Plain text, words AND-ed |
PHFTS | phraseto_tsquery | Plain text as a phrase |
WFTS | websearch_to_tsquery | Google-like syntax (-term, "phrase") |
Language modifiers (fts(english).term) are not supported in this release.
Reading totals from Content-Range
PostgREST returns a bare array body and reports the total count in the Content-Range HTTP response header. Opt in via Prefer: count=exact on the request, then pass the headers to paginate():
this._http.get<User[]>(uri, {
observe: 'response',
headers: { 'Prefer': 'count=exact' }
}).subscribe(response => {
const collection = this._pagination.paginate(response.body, response.headers);
// collection.total, collection.page, collection.lastPage are populated
});
The second argument accepts Angular's HttpHeaders, the native Headers class, or a plain Record<string, string>. Omitting the header is tolerated — the collection still populates data and page but leaves total / lastPage undefined.
RANGE-header pagination
PostgREST also accepts pagination via the Range HTTP request header instead of URL query params. Opt in via IConfig.pagination:
import { DriverEnum, PaginationModeEnum, provideNgQubee } from 'ng-qubee';
provideNgQubee({
driver: DriverEnum.POSTGREST,
pagination: PaginationModeEnum.RANGE
});
When RANGE is active, generateUri() omits limit and offset from the URL. NgQubeeService.paginationHeaders() returns the headers to apply:
const uri = await firstValueFrom(qb.generateUri());
const extraHeaders = qb.paginationHeaders(); // { 'Range-Unit': 'items', 'Range': '0-9' }
this._http.get<User[]>(uri, {
observe: 'response',
headers: { 'Prefer': 'count=exact', ...extraHeaders }
}).subscribe(resp => this._pagination.paginate(resp.body, resp.headers));
paginationHeaders() returns null for any driver that doesn't use header-based pagination — safe to spread unconditionally.
Feature matrix
| Method | Supported? | Notes |
|---|---|---|
addFilter / deleteFilters | ✓ | Implicit eq; multi-value becomes in.(...) |
addFilterOperator / deleteOperatorFilters | ✓ | All 16 operators including FTS/PLFTS/PHFTS/WFTS |
addSort / deleteSorts | ✓ | Emits order=col.asc,col.desc |
addSelect / deleteSelect | ✓ | Flat column selection |
setLimit / setPage | ✓ | offset derived from page (QUERY) or Range header (RANGE) |
addFields / deleteFields / deleteFieldsByModel | ✗ | Use addSelect for column projection |
addIncludes / deleteIncludes | ✗ | Embedded resources via select=col,rel(*) tracked as #66 |
setSearch / deleteSearch | ✗ | Use addFilterOperator(col, FilterOperatorEnum.FTS, term) instead |