Skip to main content
Version: next

Feathers Driver

Targets FeathersJS — the realtime/REST application framework for Node.js, with the dollar-prefixed query syntax shared by all Feathers database adapters (@feathersjs/knex, @feathersjs/mongodb, @feathersjs/memory, …).

Configure

import { DriverEnum, provideNgQubee } from 'ng-qubee';

bootstrapApplication(AppComponent, {
providers: [provideNgQubee({ driver: DriverEnum.FEATHERS })]
});

Wire format

ConcernOutput
Filters (single value)field=value (bare exact match)
Filters (multi-value)field[$in][0]=v1&field[$in][1]=v2
Operator filtersfield[$op]=value — see below
Sort$sort[field]=1 (ASC) / $sort[field]=-1 (DESC)
Select$select[0]=col1&$select[1]=col2
Pagination$limit=N&$skip=M (offset-based, skip = (page − 1) × limit)

The dollar-prefixed system params ($limit, $skip, $sort, $select) are fixed by the Feathers adapter-commons query parser and ignore request key overrides — the dollar prefix is how Feathers tells system params apart from filter fields.

Pagination is offset-based on the wire, but your state stays page-based: setPage(3) with setLimit(10) emits $limit=10&$skip=20.

Operator filters

FilterOperatorEnum translates to Feathers' $operator syntax:

import { FilterOperatorEnum } from 'ng-qubee';

qb.addFilterOperator('age', FilterOperatorEnum.GTE, 18); // age[$gte]=18
qb.addFilterOperator('age', FilterOperatorEnum.EQ, 18); // age=18
qb.addFilterOperator('id', FilterOperatorEnum.IN, 1, 2, 3); // id[$in][0]=1&id[$in][1]=2&id[$in][2]=3
qb.addFilterOperator('status', FilterOperatorEnum.NOT, 'draft'); // status[$ne]=draft
qb.addFilterOperator('status', FilterOperatorEnum.NOT, 'a', 'b'); // status[$nin][0]=a&status[$nin][1]=b
qb.addFilterOperator('price', FilterOperatorEnum.BTW, 10, 50); // price[$gte]=10&price[$lte]=50

Translation table

FilterOperatorEnumFeathers expression
EQbare field=value (no operator wrapper)
GT / GTE / LT / LTE[$gt] / [$gte] / [$lt] / [$lte]
IN[$in][N]= (one indexed param per value)
BTW[$gte] + [$lte] pair on the same field (arity-checked)
NOT (single)[$ne]
NOT (multi)[$nin][N]= (one indexed param per value)
CONTAINS / ILIKE / SWunsupported — LIKE-style matching is adapter-specific ($like, $iLike, $regex), not part of the common syntax; throws UnsupportedFilterOperatorError
NULLunsupported — no null-check operator on the wire; throws UnsupportedFilterOperatorError
FTS / PHFTS / PLFTS / WFTSunsupported — throws UnsupportedFilterOperatorError

Feathers' $or top-level operator has no fluent-method counterpart and is not exposed.

Value shape rules

BTW requires exactly 2 values (min, max) — enforced at call time with InvalidFilterOperatorValueError. Other operators leave shape validation to the server.

Feature matrix

MethodSupported?Notes
addFilter / deleteFiltersBare exact match (single) or [$in] (multi)
addFilterOperator / deleteOperatorFiltersSee translation table above
addSort / deleteSorts$sort[field]=1|-1 map, multi-field
setLimit / setPage$limit + derived $skip
addSelect / deleteSelect$select[N]= indexed array
addFields / deleteFields / deleteFieldsByModelNo per-model field selection
addIncludes / deleteIncludesRelation loading is resolver-side in Feathers, no query param
addEmbedded / deleteEmbeddedThrows UnsupportedEmbeddedError
setSearch / deleteSearchNo global search param in the common syntax

Response shape

Feathers database adapters return an offset-based envelope when pagination is enabled on the service:

{
"total": 48,
"limit": 10,
"skip": 10,
"data": [{ "id": 11, "text": "Hello" }]
}

FeathersResponseStrategy maps total → total and limit → perPage, then derives position arithmetically — the envelope carries no page number and no navigation URLs:

  • page is ⌊skip ÷ limit⌋ + 1 (a zero or missing limit — e.g. a $limit=0 count-only query — falls back to page 1).
  • lastPage is ceil(total ÷ limit).
  • from/to are 1-indexed offsets from skip and the item count of the current page (from = skip + 1, to = skip + data.length); both stay undefined on an empty page.

The firstPageUrl/prevPageUrl/nextPageUrl/lastPageUrl slots on PaginatedCollection stay undefined.

The data / total / limit key paths are configurable (the skip key is fixed by the envelope):

provideNgQubee({
driver: DriverEnum.FEATHERS,
response: {
data: 'results',
perPage: 'pageSize',
total: 'count'
}
});

Defaults are encoded in FeathersResponseOptions.