Skip to main content
Version: next

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

ConcernOutput
Filters (single value)col=eq.value
Filters (multi-value)col=in.(v1,v2,v3)
Operator filtersfull FilterOperatorEnum mapping — see below
Sortorder=col1.asc,col2.desc
Flat selectselect=col1,col2
Paginationlimit=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:

  • BTW requires exactly 2 values ([min, max]).
  • NULL requires exactly 1 boolean value (trueIS NULL, falseIS NOT NULL).

Other operators leave shape validation to the server.

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
OperatorSQL functionMeaning
FTSto_tsqueryRaw tsquery syntax (advanced)
PLFTSplainto_tsqueryPlain text, words AND-ed
PHFTSphraseto_tsqueryPlain text as a phrase
WFTSwebsearch_to_tsqueryGoogle-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

MethodSupported?Notes
addFilter / deleteFiltersImplicit eq; multi-value becomes in.(...)
addFilterOperator / deleteOperatorFiltersAll 16 operators including FTS/PLFTS/PHFTS/WFTS
addSort / deleteSortsEmits order=col.asc,col.desc
addSelect / deleteSelectFlat column selection
setLimit / setPageoffset derived from page (QUERY) or Range header (RANGE)
addFields / deleteFields / deleteFieldsByModelUse addSelect for column projection
addIncludes / deleteIncludesEmbedded resources via select=col,rel(*) tracked as #66
setSearch / deleteSearchUse addFilterOperator(col, FilterOperatorEnum.FTS, term) instead