OData Driver
ArchivedThese are the docs for ng-qubee 3.8. Read the 4.0 docs for @qubeejs/angular.
Targets OData v4 — the OASIS-standard query protocol primarily adopted in the Microsoft/.NET ecosystem (ASP.NET Core OData, SAP, Microsoft Graph), with implementations in Java, Node.js, and others.
Configure
Section titled “Configure”import { DriverEnum, provideNgQubee } from 'ng-qubee';
bootstrapApplication(AppComponent, { providers: [provideNgQubee({ driver: DriverEnum.ODATA })]});Wire format
Section titled “Wire format”| Concern | Output |
|---|---|
| Filters (single value) | $filter=field eq 'value' |
| Filters (multi-value) | $filter=field in ('v1','v2') |
| Filters (combined) | and-joined: $filter=status eq 'active' and price ge 100 |
| Operator filters | full FilterOperatorEnum mapping — see below |
| Sort | $orderby=likeCount asc,createdDate desc |
| Select | $select=col1,col2 |
| Expand | $expand=rel,other($select=col1,col2) |
| Search | $search=term |
| Pagination | $count=true&$top=N&$skip=M ($skip omitted on page 1) |
All filter terms — simple and operator alike — merge into one $filter= parameter, joined with and. The $-prefixed system query option names are fixed by the OData specification and ignore any request key overrides.
String literals are single-quoted with embedded quotes doubled (name eq 'O''Brien'); numbers and booleans are emitted bare.
Operator filters
Section titled “Operator filters”FilterOperatorEnum translates to OData’s expression language:
import { FilterOperatorEnum } from 'ng-qubee';
qb.addFilterOperator('likeCount', FilterOperatorEnum.GTE, 4); // likeCount ge 4qb.addFilterOperator('title', FilterOperatorEnum.CONTAINS, 'world'); // contains(title,'world')qb.addFilterOperator('title', FilterOperatorEnum.ILIKE, 'World'); // contains(tolower(title),tolower('World'))qb.addFilterOperator('title', FilterOperatorEnum.SW, 'Intro'); // startswith(title,'Intro')qb.addFilterOperator('id', FilterOperatorEnum.IN, 1, 2, 3); // id in (1,2,3)qb.addFilterOperator('status', FilterOperatorEnum.NOT, 'draft'); // status ne 'draft'qb.addFilterOperator('status', FilterOperatorEnum.NOT, 'a', 'b'); // status ne 'a' and status ne 'b'qb.addFilterOperator('deletedAt', FilterOperatorEnum.NULL, true); // deletedAt eq nullqb.addFilterOperator('deletedAt', FilterOperatorEnum.NULL, false); // deletedAt ne nullqb.addFilterOperator('price', FilterOperatorEnum.BTW, 10, 50); // price ge 10 and price le 50Translation table
Section titled “Translation table”FilterOperatorEnum |
OData expression |
|---|---|
EQ |
eq |
GT / GTE / LT / LTE |
gt / ge / lt / le |
CONTAINS |
contains(field,'val') |
ILIKE |
contains(tolower(field),tolower('val')) (case-insensitive contains) |
IN |
field in ('v1','v2') (OData v4.01 list operator) |
SW |
startswith(field,'val') |
BTW |
two AND-ed terms (field ge min and field le max, arity-checked) |
NOT (single) |
ne |
NOT (multi) |
one ne term per value, AND-ed |
NULL (true) |
field eq null |
NULL (false) |
field ne null |
FTS / PHFTS / PLFTS / WFTS |
unsupported — throws UnsupportedFilterOperatorError |
Value shape rules
Section titled “Value shape rules”Enforced at call time — both throw InvalidFilterOperatorValueError:
BTWrequires exactly 2 values (min,max).NULLrequires exactly 1 boolean value (true→eq null,false→ne null).
Other operators leave shape validation to the server.
Expanding relations
Section titled “Expanding relations”Both addIncludes and addEmbedded fold into the single $expand= parameter:
qb.addIncludes('orders', 'profile'); // $expand=orders,profileqb.addEmbedded('orders', 'id', 'amount'); // $expand=orders($select=id,amount)A relation present in both folds into the embedded fragment, which carries the column projection.
Feature matrix
Section titled “Feature matrix”| Method | Supported? | Notes |
|---|---|---|
addFilter / deleteFilters |
✓ | Folds to eq (single) or in list (multi) |
addFilterOperator / deleteOperatorFilters |
✓ | See translation table above |
addSort / deleteSorts |
✓ | $orderby=field asc,other desc |
setLimit / setPage |
✓ | $top + $skip (derived from page) |
addSelect / deleteSelect |
✓ | $select=col1,col2 |
addFields / deleteFields / deleteFieldsByModel |
✗ | No per-model field selection |
addIncludes / deleteIncludes |
✓ | Bare $expand=rel fragments |
addEmbedded / deleteEmbedded |
✓ | $expand=rel($select=col1,col2) inline projection |
setSearch / deleteSearch |
✓ | $search=term free-text search |
Response shape
Section titled “Response shape”OData collection responses use @-annotated envelope keys:
{ "@odata.context": "https://api.example.com/$metadata#Products", "@odata.count": 100, "@odata.nextLink": "https://api.example.com/Products?$count=true&$top=10&$skip=30", "value": [{ "id": 21, "name": "Keyboard" }]}The body carries no current-page or page-size field, so OdataResponseStrategy derives them from the @odata.nextLink URL:
perPagecomes from the link’s$topparam (falling back to the item count of the current — necessarily full — page).currentPageis$skip ÷ perPage— the next page starts where the current one ends.lastPageisceil(total ÷ perPage).
Without a usable link — the last page, or $skiptoken-based server-driven paging — the strategy falls back to page 1, which is only guaranteed correct for single-page results. Relative nextLink values (permitted by the spec) are handled.
Key paths are configurable for servers that rename the envelope:
provideNgQubee({ driver: DriverEnum.ODATA, response: { data: 'items', nextPageUrl: 'nextLink', total: 'totalCount' }});Defaults are encoded in OdataResponseOptions.