ng-qubee 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,36 +40,52 @@ declare class PaginatedCollection<T extends IPaginatedObject> {
40
40
  }
41
41
 
42
42
  /**
43
- * Enum representing the available pagination driver types
43
+ * Configuration interface for customizing request query parameter key names
44
44
  *
45
- * Each driver encapsulates the full format knowledge for both
46
- * request building (URI generation) and response parsing.
45
+ * Each property maps a logical query concept to the actual query parameter name
46
+ * used in the generated URI. The defaults depend on the selected driver.
47
47
  */
48
- declare enum DriverEnum {
49
- DRF = "drf",
50
- JSON_API = "json-api",
51
- LARAVEL = "laravel",
52
- NESTJS = "nestjs",
53
- POSTGREST = "postgrest",
54
- SPATIE = "spatie",
55
- STRAPI = "strapi"
48
+ interface IQueryBuilderConfig {
49
+ /** Key for the appends parameter (Laravel only, default: 'append') */
50
+ appends?: string;
51
+ /** Key for the fields parameter (Laravel: 'fields', NestJS: 'select') */
52
+ fields?: string;
53
+ /** Key for the filters parameter (default: 'filter') */
54
+ filters?: string;
55
+ /** Key for the includes parameter (Laravel only, default: 'include') */
56
+ includes?: string;
57
+ /** Key for the limit parameter (default: 'limit') */
58
+ limit?: string;
59
+ /** Key for the page parameter (default: 'page') */
60
+ page?: string;
61
+ /** Key for the search parameter (NestJS only, default: 'search') */
62
+ search?: string;
63
+ /** Key for the select parameter (NestJS only, default: 'select') */
64
+ select?: string;
65
+ /** Key for the sort parameter (Laravel: 'sort', NestJS: 'sortBy') */
66
+ sort?: string;
67
+ /** Key for the sortBy parameter (NestJS only, default: 'sortBy') */
68
+ sortBy?: string;
56
69
  }
57
70
 
58
71
  /**
59
- * Enum representing the wire-level pagination mechanism
60
- *
61
- * `QUERY` (default) — the request strategy emits `limit` and `offset` (or
62
- * equivalent) query parameters on the URL.
72
+ * Resolved query parameter key names with defaults applied
63
73
  *
64
- * `RANGE` the request strategy omits URL-based pagination and the
65
- * consumer instead applies HTTP request headers returned by
66
- * `NgQubeeService.paginationHeaders()`. Currently honoured only by the
67
- * PostgREST driver, which maps it to `Range-Unit: items` + `Range: 0-9`.
68
- * Other drivers ignore the setting.
74
+ * Maps logical query concepts to the actual query parameter names
75
+ * used in the generated URI. Unset values fall back to defaults.
69
76
  */
70
- declare enum PaginationModeEnum {
71
- QUERY = "query",
72
- RANGE = "range"
77
+ declare class QueryBuilderOptions {
78
+ readonly appends: string;
79
+ readonly fields: string;
80
+ readonly filters: string;
81
+ readonly includes: string;
82
+ readonly limit: string;
83
+ readonly page: string;
84
+ readonly search: string;
85
+ readonly select: string;
86
+ readonly sort: string;
87
+ readonly sortBy: string;
88
+ constructor(options: IQueryBuilderConfig);
73
89
  }
74
90
 
75
91
  /**
@@ -109,32 +125,264 @@ interface IPaginationConfig {
109
125
  }
110
126
 
111
127
  /**
112
- * Configuration interface for customizing request query parameter key names
128
+ * Resolved response field key names with defaults applied
113
129
  *
114
- * Each property maps a logical query concept to the actual query parameter name
115
- * used in the generated URI. The defaults depend on the selected driver.
130
+ * Maps logical pagination concepts to the actual key names
131
+ * used in the API response. Unset values fall back to Laravel defaults.
132
+ *
133
+ * For NestJS responses, use dot-notation paths:
134
+ * ```typescript
135
+ * new ResponseOptions({
136
+ * currentPage: 'meta.currentPage',
137
+ * total: 'meta.totalItems'
138
+ * });
139
+ * ```
116
140
  */
117
- interface IQueryBuilderConfig {
118
- /** Key for the appends parameter (Laravel only, default: 'append') */
119
- appends?: string;
120
- /** Key for the fields parameter (Laravel: 'fields', NestJS: 'select') */
121
- fields?: string;
122
- /** Key for the filters parameter (default: 'filter') */
123
- filters?: string;
124
- /** Key for the includes parameter (Laravel only, default: 'include') */
125
- includes?: string;
126
- /** Key for the limit parameter (default: 'limit') */
127
- limit?: string;
128
- /** Key for the page parameter (default: 'page') */
129
- page?: string;
130
- /** Key for the search parameter (NestJS only, default: 'search') */
131
- search?: string;
132
- /** Key for the select parameter (NestJS only, default: 'select') */
133
- select?: string;
134
- /** Key for the sort parameter (Laravel: 'sort', NestJS: 'sortBy') */
135
- sort?: string;
136
- /** Key for the sortBy parameter (NestJS only, default: 'sortBy') */
137
- sortBy?: string;
141
+ declare class ResponseOptions {
142
+ readonly currentPage: string;
143
+ readonly data: string;
144
+ readonly firstPageUrl: string;
145
+ readonly from: string;
146
+ readonly lastPage: string;
147
+ readonly lastPageUrl: string;
148
+ readonly nextPageUrl: string;
149
+ readonly path: string;
150
+ readonly perPage: string;
151
+ readonly prevPageUrl: string;
152
+ readonly to: string;
153
+ readonly total: string;
154
+ constructor(options: IPaginationConfig);
155
+ }
156
+ /**
157
+ * Pre-configured ResponseOptions for the API Platform (Symfony) driver
158
+ *
159
+ * Uses dot-notation paths into the Hydra/JSON-LD envelope — the Hydra
160
+ * keys contain colons but no dots, so `hydra:view.hydra:next` traverses
161
+ * `response['hydra:view']['hydra:next']`. The `path` slot points at the
162
+ * view's `@id`, which the strategy parses for the current page and page
163
+ * size; `currentPage` / `perPage` / `lastPage` have no body field and
164
+ * default to empty paths (derived from the view URLs instead).
165
+ */
166
+ declare class ApiPlatformResponseOptions extends ResponseOptions {
167
+ constructor(options: IPaginationConfig);
168
+ }
169
+ /**
170
+ * Pre-configured ResponseOptions for the Directus driver
171
+ *
172
+ * The Directus envelope is `{ data, meta: { total_count, filter_count } }`
173
+ * (with `meta=total_count,filter_count` requested — the request strategy
174
+ * always emits it). `total` defaults to `meta.filter_count`, the count of
175
+ * items matching the current filter; point it at `meta.total_count` via
176
+ * `IPaginationConfig` for the unfiltered collection size. The envelope
177
+ * names no current page, page size, or navigation URLs, so those paths
178
+ * default to empty strings — the strategy falls back to page 1 and
179
+ * derives `lastPage`/`from`/`to` only when the response provably holds
180
+ * the whole filtered set. All paths are overridable (dot notation
181
+ * supported) for custom wrappers that do include paging fields.
182
+ */
183
+ declare class DirectusResponseOptions extends ResponseOptions {
184
+ constructor(options: IPaginationConfig);
185
+ }
186
+ /**
187
+ * Pre-configured ResponseOptions for the Django REST Framework (DRF) driver
188
+ *
189
+ * DRF's `PageNumberPagination` envelope is `{ count, next, previous,
190
+ * results }`, with no body field naming the current page, per-page, or
191
+ * last-page. The strategy parses those from the `next` / `previous`
192
+ * URLs, so the corresponding key paths default to empty strings; the
193
+ * strategy ignores `options.currentPage`, `options.perPage`,
194
+ * `options.lastPage`, `options.from`, `options.to`, `options.path`,
195
+ * `options.firstPageUrl`, and `options.lastPageUrl`.
196
+ */
197
+ declare class DrfResponseOptions extends ResponseOptions {
198
+ constructor(options: IPaginationConfig);
199
+ }
200
+ /**
201
+ * Pre-configured ResponseOptions for the FeathersJS driver
202
+ *
203
+ * The Feathers adapter envelope is `{ total, limit, skip, data }` —
204
+ * offset-based, with no page number and no navigation URLs. `perPage`
205
+ * maps to the envelope's `limit` key and `total` to `total`; the
206
+ * strategy derives `currentPage` / `lastPage` / `from` / `to` from
207
+ * `skip` and `limit`, so the corresponding key paths default to empty
208
+ * strings (the `skip` key itself is fixed by the envelope and read
209
+ * directly by the strategy).
210
+ */
211
+ declare class FeathersResponseOptions extends ResponseOptions {
212
+ constructor(options: IPaginationConfig);
213
+ }
214
+ /**
215
+ * Pre-configured ResponseOptions for the JSON:API driver
216
+ *
217
+ * Uses dot-notation paths to access nested values in the JSON:API response format.
218
+ * JSON:API meta key names vary by implementation; these defaults cover the most
219
+ * common conventions and can be fully customised via `IPaginationConfig`.
220
+ */
221
+ declare class JsonApiResponseOptions extends ResponseOptions {
222
+ constructor(options: IPaginationConfig);
223
+ }
224
+ /**
225
+ * Pre-configured ResponseOptions for the json-server driver
226
+ *
227
+ * The json-server v1 envelope is `{ first, prev, next, last, pages,
228
+ * items, data }`, where `first`/`prev`/`next`/`last` are **page
229
+ * numbers**, not URLs — the strategy reads `prev`/`next` directly for
230
+ * position derivation and leaves the URL slots `undefined`, so the
231
+ * navigation-URL paths default to empty strings. `total` maps to
232
+ * `items` and `lastPage` to `pages`; `currentPage` and `perPage` have
233
+ * no body field and are derived.
234
+ */
235
+ declare class JsonServerResponseOptions extends ResponseOptions {
236
+ constructor(options: IPaginationConfig);
237
+ }
238
+ /**
239
+ * Pre-configured ResponseOptions for the NestJS driver
240
+ *
241
+ * Uses dot-notation paths to access nested values in the NestJS response format.
242
+ */
243
+ declare class NestjsResponseOptions extends ResponseOptions {
244
+ constructor(options: IPaginationConfig);
245
+ }
246
+ /**
247
+ * Pre-configured ResponseOptions for the @nestjsx/crud driver
248
+ *
249
+ * The `getMany` envelope is flat: `{ data, count, total, page,
250
+ * pageCount }`. `perPage` defaults to the `count` field — the number of
251
+ * entities on the **current** page, which equals the requested limit on
252
+ * every page except a partial last one. The envelope carries no
253
+ * `from`/`to` indices and no navigation links, so those paths default to
254
+ * empty strings (the strategy derives `from`/`to` and leaves the URLs
255
+ * `undefined`); consumers can override any path via `IPaginationConfig`.
256
+ */
257
+ declare class NestjsxCrudResponseOptions extends ResponseOptions {
258
+ constructor(options: IPaginationConfig);
259
+ }
260
+ /**
261
+ * Pre-configured ResponseOptions for the OData v4 driver
262
+ *
263
+ * The OData collection envelope is `{ "@odata.count", "@odata.nextLink",
264
+ * "value" }` — flat keys that contain **literal dots**, so the strategy
265
+ * reads them with flat bracket access (never dot-path traversal). No body
266
+ * field names the current page, per-page, or last-page; the strategy
267
+ * derives those from the `@odata.nextLink` URL's `$skip` / `$top`
268
+ * params, so the corresponding key paths default to empty strings and
269
+ * are ignored.
270
+ */
271
+ declare class OdataResponseOptions extends ResponseOptions {
272
+ constructor(options: IPaginationConfig);
273
+ }
274
+ /**
275
+ * Pre-configured ResponseOptions for the Payload CMS driver
276
+ *
277
+ * The envelope is the flat `mongoose-paginate-v2` shape: `{ docs,
278
+ * totalDocs, limit, totalPages, page, pagingCounter, hasPrevPage,
279
+ * hasNextPage, prevPage, nextPage }`. `pagingCounter` is the 1-indexed
280
+ * offset of the first doc on the page and maps onto `from`; `to` has no
281
+ * body field and is derived. `prevPage`/`nextPage` are page numbers,
282
+ * not URLs, so the navigation-URL paths default to empty strings. All
283
+ * paths are overridable via `IPaginationConfig` (dot notation
284
+ * supported) for custom wrappers.
285
+ */
286
+ declare class PayloadResponseOptions extends ResponseOptions {
287
+ constructor(options: IPaginationConfig);
288
+ }
289
+ /**
290
+ * Pre-configured ResponseOptions for the PocketBase driver
291
+ *
292
+ * The records-list envelope is flat: `{ page, perPage, totalItems,
293
+ * totalPages, items }`. The envelope carries no `from`/`to` indices and
294
+ * no navigation links, so those paths default to empty strings (the
295
+ * strategy derives `from`/`to` from `page` × `perPage` and leaves the
296
+ * URLs `undefined`); all paths are overridable via `IPaginationConfig`
297
+ * (dot notation supported) for custom wrappers.
298
+ */
299
+ declare class PocketbaseResponseOptions extends ResponseOptions {
300
+ constructor(options: IPaginationConfig);
301
+ }
302
+ /**
303
+ * Pre-configured ResponseOptions for the Sieve (.NET) driver
304
+ *
305
+ * Sieve defines no response envelope (it returns an `IQueryable` the
306
+ * developer wraps), so these defaults target the common hand-rolled
307
+ * `PagedResult<T>` shape: `{ data, page, pageSize, total, totalPages }`.
308
+ * Every path is overridable via `IPaginationConfig` — dot notation is
309
+ * supported, so nested wrappers (`meta.page`, `pagination.total`) map
310
+ * without subclassing. `from`/`to` default to empty paths and are
311
+ * derived; the navigation-URL slots resolve to `undefined` unless paths
312
+ * are provided.
313
+ */
314
+ declare class SieveResponseOptions extends ResponseOptions {
315
+ constructor(options: IPaginationConfig);
316
+ }
317
+ /**
318
+ * Pre-configured ResponseOptions for the Spring Data REST driver
319
+ *
320
+ * Uses dot-notation paths into the HAL envelope: pagination metadata
321
+ * lives under `page.*` and navigation links under `_links.*.href`.
322
+ * `currentPage` points at the **0-indexed** `page.number`; the strategy
323
+ * adds 1 when reading it. `data` defaults to plain `_embedded` because
324
+ * the collection key underneath is the resource rel name (e.g.
325
+ * `_embedded.users`) and cannot be known statically — the strategy picks
326
+ * the first array inside; pin an exact path via `IPaginationConfig` when
327
+ * needed. `from`/`to` default to empty paths and are derived.
328
+ */
329
+ declare class SpringResponseOptions extends ResponseOptions {
330
+ constructor(options: IPaginationConfig);
331
+ }
332
+ /**
333
+ * Pre-configured ResponseOptions for the Strapi driver
334
+ *
335
+ * Uses dot-notation paths to access the nested `meta.pagination.*` envelope
336
+ * Strapi v4/v5 emits. Strapi does not include navigation links by default,
337
+ * so the URL paths point at locations that will resolve to `undefined`
338
+ * unless the consumer overrides them.
339
+ */
340
+ declare class StrapiResponseOptions extends ResponseOptions {
341
+ constructor(options: IPaginationConfig);
342
+ }
343
+
344
+ /**
345
+ * Enum representing the available pagination driver types
346
+ *
347
+ * Each driver encapsulates the full format knowledge for both
348
+ * request building (URI generation) and response parsing.
349
+ */
350
+ declare enum DriverEnum {
351
+ API_PLATFORM = "api-platform",
352
+ DIRECTUS = "directus",
353
+ DRF = "drf",
354
+ FEATHERS = "feathers",
355
+ JSON_API = "json-api",
356
+ JSON_SERVER = "json-server",
357
+ LARAVEL = "laravel",
358
+ NESTJS = "nestjs",
359
+ NESTJSX_CRUD = "nestjsx-crud",
360
+ ODATA = "odata",
361
+ PAYLOAD = "payload",
362
+ POCKETBASE = "pocketbase",
363
+ POSTGREST = "postgrest",
364
+ SIEVE = "sieve",
365
+ SPATIE = "spatie",
366
+ SPRING = "spring",
367
+ STRAPI = "strapi",
368
+ WORDPRESS = "wordpress"
369
+ }
370
+
371
+ /**
372
+ * Enum representing the wire-level pagination mechanism
373
+ *
374
+ * `QUERY` (default) — the request strategy emits `limit` and `offset` (or
375
+ * equivalent) query parameters on the URL.
376
+ *
377
+ * `RANGE` — the request strategy omits URL-based pagination and the
378
+ * consumer instead applies HTTP request headers returned by
379
+ * `NgQubeeService.paginationHeaders()`. Currently honoured only by the
380
+ * PostgREST driver, which maps it to `Range-Unit: items` + `Range: 0-9`.
381
+ * Other drivers ignore the setting.
382
+ */
383
+ declare enum PaginationModeEnum {
384
+ QUERY = "query",
385
+ RANGE = "range"
138
386
  }
139
387
 
140
388
  /**
@@ -349,6 +597,19 @@ interface ISort {
349
597
  order: SortEnum;
350
598
  }
351
599
 
600
+ /**
601
+ * Embedded-resource selection map (PostgREST only)
602
+ *
603
+ * Maps a related table / foreign-key name (as PostgREST sees it) to the
604
+ * columns to project from it. An empty array means "all columns" and
605
+ * emits `relation(*)`; a non-empty array emits `relation(col1,col2)`.
606
+ * The PostgREST request strategy splices these fragments into the single
607
+ * `select=` query parameter alongside flat columns from `addSelect`.
608
+ */
609
+ type Embedded = {
610
+ [relation: string]: string[];
611
+ };
612
+
352
613
  /**
353
614
  * Represents the complete query builder state
354
615
  *
@@ -358,6 +619,8 @@ interface ISort {
358
619
  interface IQueryBuilderState {
359
620
  /** The base URL to prepend to generated URIs */
360
621
  baseUrl: string;
622
+ /** Embedded-resource selection (PostgREST only) */
623
+ embedded: Embedded;
361
624
  /** Per-model field selection (Spatie only) */
362
625
  fields: IFields;
363
626
  /** Simple key-value filters (Spatie and NestJS) */
@@ -395,6 +658,8 @@ interface IQueryBuilderState {
395
658
  * strategy class — `NgQubeeService` does not need to be touched.
396
659
  */
397
660
  interface IStrategyCapabilities {
661
+ /** Embedded-resource selection inside `select` (PostgREST `select=col,rel(col1)`) */
662
+ readonly embedded: boolean;
398
663
  /** Per-model field selection (e.g. JSON:API `fields[type]=col1,col2`) */
399
664
  readonly fields: boolean;
400
665
  /** Simple key-value filters (e.g. `filter.status=active`) */
@@ -411,26 +676,6 @@ interface IStrategyCapabilities {
411
676
  readonly sort: boolean;
412
677
  }
413
678
 
414
- /**
415
- * Resolved query parameter key names with defaults applied
416
- *
417
- * Maps logical query concepts to the actual query parameter names
418
- * used in the generated URI. Unset values fall back to defaults.
419
- */
420
- declare class QueryBuilderOptions {
421
- readonly appends: string;
422
- readonly fields: string;
423
- readonly filters: string;
424
- readonly includes: string;
425
- readonly limit: string;
426
- readonly page: string;
427
- readonly search: string;
428
- readonly select: string;
429
- readonly sort: string;
430
- readonly sortBy: string;
431
- constructor(options: IQueryBuilderConfig);
432
- }
433
-
434
679
  /**
435
680
  * Strategy interface for building request URIs
436
681
  *
@@ -556,6 +801,21 @@ declare class NestService {
556
801
  * @private
557
802
  */
558
803
  private _validateResourceName;
804
+ /**
805
+ * Add embedded-resource selections to the request (PostgREST only)
806
+ * Automatically prevents duplicate columns for each relation
807
+ *
808
+ * An empty column array means "all columns" (`relation(*)`); merging an
809
+ * empty array into a relation that already has explicit columns keeps
810
+ * the explicit columns.
811
+ *
812
+ * @param {Embedded} embedded - Object mapping relation names to arrays of columns to project
813
+ * @return {void}
814
+ * @example
815
+ * service.addEmbedded({ author: ['id', 'name'] });
816
+ * service.addEmbedded({ comments: [] });
817
+ */
818
+ addEmbedded(embedded: Embedded): void;
559
819
  /**
560
820
  * Add selectable fields for the given model to the request
561
821
  * Automatically prevents duplicate fields for each model
@@ -621,6 +881,18 @@ declare class NestService {
621
881
  * service.addSort({ field: 'name', order: SortEnum.ASC });
622
882
  */
623
883
  addSort(sort: ISort): void;
884
+ /**
885
+ * Remove embedded-resource relations from the state (PostgREST only)
886
+ *
887
+ * Removes the whole relation entry, columns included.
888
+ *
889
+ * @param {...string[]} relations - Relation names to remove
890
+ * @return {void}
891
+ * @example
892
+ * service.deleteEmbedded('author');
893
+ * service.deleteEmbedded('comments', 'tags');
894
+ */
895
+ deleteEmbedded(...relations: string[]): void;
624
896
  /**
625
897
  * Remove fields for the given model
626
898
  * Uses deep cloning to prevent mutations to the original state
@@ -762,10 +1034,33 @@ declare class NgQubeeService {
762
1034
  */
763
1035
  private _assertCapability;
764
1036
  /**
765
- * Add fields to the select statement for the given model (JSON:API and Spatie only)
1037
+ * Add an embedded resource to the select statement (PostgREST only)
766
1038
  *
767
- * @param model - Model that holds the fields
768
- * @param fields - Fields to select
1039
+ * Splices `relation(col1,col2)` into the single `select=` query
1040
+ * parameter alongside flat columns from `addSelect`. Omit the columns
1041
+ * to project all of them (`relation(*)`):
1042
+ *
1043
+ * ```
1044
+ * qb.addEmbedded('author', 'id', 'name')
1045
+ * .addEmbedded('comments')
1046
+ * .addSelect('title');
1047
+ * // → select=title,author(id,name),comments(*)
1048
+ * ```
1049
+ *
1050
+ * Calling repeatedly with the same relation merge-dedups the columns.
1051
+ * Does not reset the page (column shape change, not record-set change).
1052
+ *
1053
+ * @param {string} relation - The related table / foreign-key name as PostgREST sees it
1054
+ * @param {string[]} columns - Optional column projection; omit for `relation(*)`
1055
+ * @returns {this}
1056
+ * @throws {UnsupportedEmbeddedError} If the active driver does not support embedded resources
1057
+ */
1058
+ addEmbedded(relation: string, ...columns: string[]): this;
1059
+ /**
1060
+ * Add fields to the select statement for the given model (JSON:API and Spatie only)
1061
+ *
1062
+ * @param model - Model that holds the fields
1063
+ * @param fields - Fields to select
769
1064
  * @returns {this}
770
1065
  * @throws {UnsupportedFieldSelectionError} If the active driver does not support per-model field selection
771
1066
  */
@@ -827,6 +1122,16 @@ declare class NgQubeeService {
827
1122
  * @returns The current page number
828
1123
  */
829
1124
  currentPage(): number;
1125
+ /**
1126
+ * Remove embedded resources from the current query builder state (PostgREST only)
1127
+ *
1128
+ * Removes the whole relation entry, columns included.
1129
+ *
1130
+ * @param {string[]} relations - Relation names to remove
1131
+ * @returns {this}
1132
+ * @throws {UnsupportedEmbeddedError} If the active driver does not support embedded resources
1133
+ */
1134
+ deleteEmbedded(...relations: string[]): this;
830
1135
  /**
831
1136
  * Delete selected fields for the given models in the current query builder state (JSON:API and Spatie only)
832
1137
  *
@@ -1073,36 +1378,6 @@ type HeaderBag = {
1073
1378
  */
1074
1379
  declare function readHeader(bag: HeaderBag | null | undefined, name: string): string | null;
1075
1380
 
1076
- /**
1077
- * Resolved response field key names with defaults applied
1078
- *
1079
- * Maps logical pagination concepts to the actual key names
1080
- * used in the API response. Unset values fall back to Laravel defaults.
1081
- *
1082
- * For NestJS responses, use dot-notation paths:
1083
- * ```typescript
1084
- * new ResponseOptions({
1085
- * currentPage: 'meta.currentPage',
1086
- * total: 'meta.totalItems'
1087
- * });
1088
- * ```
1089
- */
1090
- declare class ResponseOptions {
1091
- readonly currentPage: string;
1092
- readonly data: string;
1093
- readonly firstPageUrl: string;
1094
- readonly from: string;
1095
- readonly lastPage: string;
1096
- readonly lastPageUrl: string;
1097
- readonly nextPageUrl: string;
1098
- readonly path: string;
1099
- readonly perPage: string;
1100
- readonly prevPageUrl: string;
1101
- readonly to: string;
1102
- readonly total: string;
1103
- constructor(options: IPaginationConfig);
1104
- }
1105
-
1106
1381
  /**
1107
1382
  * Strategy interface for parsing paginated API responses
1108
1383
  *
@@ -1247,6 +1522,19 @@ declare class UnselectableModelError extends Error {
1247
1522
  constructor(model: string);
1248
1523
  }
1249
1524
 
1525
+ /**
1526
+ * Error thrown when embedded resources are attempted with a driver that
1527
+ * does not support them
1528
+ *
1529
+ * Embedded-resource fetching (`select=col,relation(col1,col2)`) is a
1530
+ * PostgREST-native join mechanism and is only supported by the PostgREST
1531
+ * driver. Drivers with a standalone relation parameter expose it through
1532
+ * `addIncludes()` instead (JSON:API, Spatie, Strapi, @nestjsx/crud).
1533
+ */
1534
+ declare class UnsupportedEmbeddedError extends Error {
1535
+ constructor();
1536
+ }
1537
+
1250
1538
  /**
1251
1539
  * Error thrown when per-model field selection is attempted with a driver that does not support it
1252
1540
  *
@@ -1446,78 +1734,131 @@ declare abstract class AbstractRequestStrategy implements IRequestStrategy {
1446
1734
  }
1447
1735
 
1448
1736
  /**
1449
- * Request strategy for the JSON:API driver
1737
+ * Request strategy for the API Platform (Symfony) driver
1450
1738
  *
1451
- * Generates URIs in the JSON:API format:
1452
- * - Fields: `fields[articles]=title,body&fields[people]=name`
1453
- * - Filters: `filter[status]=active`
1454
- * - Includes: `include=author,comments.author`
1455
- * - Pagination: `page[number]=1&page[size]=15`
1456
- * - Sort: `sort=-created_at,name` (- prefix = DESC)
1739
+ * Generates URIs in [API Platform's filter format](https://api-platform.com/docs/core/filters/):
1740
+ * - Filters: `field=value` (exact); multi-value uses the array syntax
1741
+ * (`field[]=v1&field[]=v2`, OR semantics)
1742
+ * - Operator filters: bracket syntax `field[op]=value` — RangeFilter
1743
+ * (`gt`/`gte`/`lt`/`lte`/`between`), SearchFilter strategies
1744
+ * (`partial`/`ipartial`/`start`), ExistsFilter (`exists`) see the
1745
+ * mapping on `_formatOperatorSegments`
1746
+ * - Relation filtering: dot paths pass through (`author.name=John` via
1747
+ * `addFilter('author.name', 'John')`)
1748
+ * - Sorts: `order[field]=asc` / `order[field]=desc` (one param per rule)
1749
+ * - Pagination: `page=N&itemsPerPage=M`
1457
1750
  *
1458
- * @see https://jsonapi.org/format/
1751
+ * The `order` and `itemsPerPage` keys are API Platform conventions and
1752
+ * intentionally not configurable through `QueryBuilderOptions`; `page`
1753
+ * honours the existing option key (its default matches the wire format).
1754
+ *
1755
+ * Date fields use API Platform's DateFilter (`field[after]=…`,
1756
+ * `field[before]=…`) — there is no `FilterOperatorEnum` counterpart, but
1757
+ * the bracket key passes through `addFilter` directly:
1758
+ * `addFilter('createdAt[after]', '2023-01-01')`.
1759
+ *
1760
+ * `NOT` (no negation filter in API Platform core) and the
1761
+ * PostgREST-native full-text operators (`FTS`, `PHFTS`, `PLFTS`,
1762
+ * `WFTS`) throw `UnsupportedFilterOperatorError`.
1763
+ *
1764
+ * @see https://api-platform.com/docs/core/filters/
1459
1765
  */
1460
- declare class JsonApiRequestStrategy extends AbstractRequestStrategy {
1766
+ declare class ApiPlatformRequestStrategy extends AbstractRequestStrategy {
1461
1767
  /**
1462
- * Filters, sorts, includes, per-model fields — same shape as Spatie
1463
- * but with bracket-style pagination
1768
+ * Filters, operator filters, sorts — no per-model fields, no
1769
+ * includes (relations embed via serialization groups server-side),
1770
+ * no flat select, no global search parameter
1464
1771
  */
1465
1772
  readonly capabilities: IStrategyCapabilities;
1466
1773
  /**
1467
- * Emit JSON:API-format query-string segments in canonical order:
1468
- * include → fields → filters → pagination → sort
1774
+ * API Platform-native names of the two hardcoded query keys
1775
+ *
1776
+ * `order[...]` and `itemsPerPage` are fixed conventions of API
1777
+ * Platform's OrderFilter and pagination; they are intentionally not
1778
+ * configurable through `QueryBuilderOptions` and live as private
1779
+ * statics so they are visible in one place.
1780
+ */
1781
+ private static readonly _itemsPerPageKey;
1782
+ private static readonly _orderKey;
1783
+ /**
1784
+ * Emit API Platform-format query-string segments in canonical order:
1785
+ * filters → operator filters → order → page → itemsPerPage
1469
1786
  *
1470
1787
  * @param state - The current query builder state
1471
- * @param options - The query parameter key name configuration
1788
+ * @param options - The query parameter key name configuration (used
1789
+ * for `page`, whose default matches the wire format)
1472
1790
  * @returns Ordered query-string fragments
1473
1791
  */
1474
1792
  protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
1475
1793
  /**
1476
- * Append per-type field selection in bracket notation
1794
+ * Append simple filter parameters
1795
+ *
1796
+ * A single value emits the bare exact-match form (`field=value`);
1797
+ * multiple values use API Platform's array syntax with OR semantics
1798
+ * (`field[]=v1&field[]=v2`).
1477
1799
  *
1478
1800
  * @param state - The current query builder state
1479
- * @param options - The query parameter key name configuration
1480
1801
  * @param out - The accumulator the caller joins into the URI
1481
- * @throws Error if the resource is missing from the fields object
1482
- * @throws UnselectableModelError if a field type is not the resource or in includes
1483
1802
  */
1484
- private _appendFields;
1803
+ private _appendFilters;
1485
1804
  /**
1486
- * Append filter parameters in bracket notation: `filter[key]=value`
1805
+ * Append the itemsPerPage parameter
1487
1806
  *
1488
1807
  * @param state - The current query builder state
1489
- * @param options - The query parameter key name configuration
1490
1808
  * @param out - The accumulator the caller joins into the URI
1491
1809
  */
1492
- private _appendFilters;
1810
+ private _appendItemsPerPage;
1493
1811
  /**
1494
- * Append include parameter as `include=author,comments.author`
1812
+ * Append explicit operator filters in the bracket syntax
1495
1813
  *
1496
1814
  * @param state - The current query builder state
1497
- * @param options - The query parameter key name configuration
1498
1815
  * @param out - The accumulator the caller joins into the URI
1499
1816
  */
1500
- private _appendIncludes;
1817
+ private _appendOperatorFilters;
1501
1818
  /**
1502
- * Append JSON:API bracket pagination as `page[number]=1&page[size]=15`
1503
- *
1504
- * `qs.stringify` already returns the two segments joined with `&`, so we
1505
- * push the whole string as one accumulator entry — `_join` will glue
1506
- * it onto the rest with the same separator.
1819
+ * Append `order[field]=asc` / `order[field]=desc` params, one per rule
1507
1820
  *
1508
1821
  * @param state - The current query builder state
1509
- * @param options - The query parameter key name configuration
1510
1822
  * @param out - The accumulator the caller joins into the URI
1511
1823
  */
1512
- private _appendPagination;
1824
+ private _appendOrder;
1513
1825
  /**
1514
- * Append sort parameter as `sort=-field1,field2` (`-` prefix = DESC)
1826
+ * Append the page parameter
1515
1827
  *
1516
1828
  * @param state - The current query builder state
1517
1829
  * @param options - The query parameter key name configuration
1518
1830
  * @param out - The accumulator the caller joins into the URI
1519
1831
  */
1520
- private _appendSort;
1832
+ private _appendPage;
1833
+ /**
1834
+ * Translate a `FilterOperatorEnum` operator filter into one or more
1835
+ * API Platform bracket segments
1836
+ *
1837
+ * The mapping is library-canonical → API Platform-native:
1838
+ * - `EQ` → bare exact match (`field=value`, SearchFilter exact)
1839
+ * - `GT`/`GTE`/`LT`/`LTE` → RangeFilter (`field[gt]=v`, …)
1840
+ * - `BTW` → RangeFilter `field[between]=min..max` (arity-checked)
1841
+ * - `CONTAINS` → SearchFilter partial (`field[partial]=v`)
1842
+ * - `ILIKE` → SearchFilter ipartial (`field[ipartial]=v`,
1843
+ * case-insensitive)
1844
+ * - `SW` → SearchFilter start (`field[start]=v`)
1845
+ * - `IN` → array syntax (`field[]=v1&field[]=v2`)
1846
+ * - `NULL` → ExistsFilter — **inverted**: `true` (IS NULL) emits
1847
+ * `field[exists]=false`, `false` (IS NOT NULL) emits
1848
+ * `field[exists]=true`; arity- and type-checked
1849
+ *
1850
+ * `NOT` (API Platform core ships no negation filter) and PostgREST's
1851
+ * full-text-search operators (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
1852
+ * `UnsupportedFilterOperatorError`.
1853
+ *
1854
+ * @param filter - The operator filter to translate
1855
+ * @returns One or more bracket-syntax query-string segments
1856
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
1857
+ * exactly two values, or `NULL` does not receive exactly one boolean
1858
+ * @throws {UnsupportedFilterOperatorError} If the operator has no API
1859
+ * Platform equivalent
1860
+ */
1861
+ private _formatOperatorSegments;
1521
1862
  }
1522
1863
 
1523
1864
  /**
@@ -1586,153 +1927,189 @@ declare abstract class AbstractDotPathResponseStrategy implements IResponseStrat
1586
1927
  }
1587
1928
 
1588
1929
  /**
1589
- * Response strategy for the JSON:API driver
1930
+ * Response strategy for the API Platform (Symfony) driver
1931
+ *
1932
+ * Parses API Platform's default Hydra/JSON-LD collection envelope:
1590
1933
  *
1591
- * Parses JSON:API pagination responses:
1592
1934
  * ```json
1593
1935
  * {
1594
- * "data": [...],
1595
- * "meta": {
1596
- * "current-page": 1,
1597
- * "per-page": 10,
1598
- * "total": 100,
1599
- * "page-count": 10,
1600
- * "from": 1,
1601
- * "to": 10
1602
- * },
1603
- * "links": {
1604
- * "first": "url",
1605
- * "prev": "url",
1606
- * "next": "url",
1607
- * "last": "url"
1936
+ * "@context": "/contexts/Book",
1937
+ * "@type": "hydra:Collection",
1938
+ * "hydra:totalItems": 48,
1939
+ * "hydra:member": [...],
1940
+ * "hydra:view": {
1941
+ * "@id": "/books?page=3&itemsPerPage=10",
1942
+ * "hydra:first": "/books?page=1",
1943
+ * "hydra:previous": "/books?page=2",
1944
+ * "hydra:next": "/books?page=4",
1945
+ * "hydra:last": "/books?page=5"
1608
1946
  * }
1609
1947
  * }
1610
1948
  * ```
1611
1949
  *
1612
- * Default key paths are configured in `JsonApiResponseOptions`. The
1613
- * traversal algorithm (dot-notation resolution + computed `from`/`to`) is
1614
- * inherited from `AbstractDotPathResponseStrategy`; this class exists so
1615
- * `DriverEnum.JSON_API` resolves to a distinct identity at the DI layer
1616
- * even though the parsing logic is shared with NestJS.
1950
+ * The Hydra keys contain colons but no dots, so the inherited
1951
+ * dot-notation resolver traverses them cleanly (`hydra:view.hydra:next`
1952
+ * `response['hydra:view']['hydra:next']`). The body names no
1953
+ * current-page or page-size field, so both are **derived from the
1954
+ * `hydra:view` URLs**:
1617
1955
  *
1618
- * @see https://jsonapi.org/format/
1619
- */
1620
- declare class JsonApiResponseStrategy extends AbstractDotPathResponseStrategy {
1621
- }
1622
-
1623
- /**
1624
- * Request strategy for the Laravel (pagination-only) driver
1956
+ * - `currentPage` from the `page` param of the view's `@id` (the
1957
+ * `path` option slot points there); missing view → page **1**.
1958
+ * - `perPage` from the `itemsPerPage` param of the view's `@id`
1959
+ * (echoed whenever the request set it — this driver's request
1960
+ * strategy always does), falling back to the item count of a page
1961
+ * that has a `hydra:next` successor.
1962
+ * - `lastPage` from the `page` param of `hydra:last`, falling back to
1963
+ * `ceil(total ÷ perPage)`; a view-less response holding the whole
1964
+ * collection resolves to 1.
1625
1965
  *
1626
- * Generates simple pagination URIs:
1627
- * - `/{resource}?limit=N&page=N`
1966
+ * URLs are typically **relative** (`/books?page=4`) — parsing retries
1967
+ * against a placeholder base, and the links are surfaced as-is on the
1968
+ * collection. JSON:API and HAL serialization formats are out of scope
1969
+ * (use the JSON:API driver for the former).
1628
1970
  *
1629
- * Filters, sorts, fields, includes, search, and select in state are ignored.
1971
+ * @see https://api-platform.com/docs/core/pagination/
1630
1972
  */
1631
- declare class LaravelRequestStrategy extends AbstractRequestStrategy {
1973
+ declare class ApiPlatformResponseStrategy extends AbstractDotPathResponseStrategy {
1632
1974
  /**
1633
- * Pagination-only driver no filtering, sorting, or column selection
1975
+ * Parse a Hydra collection response into a PaginatedCollection
1976
+ *
1977
+ * @param response - The raw API response body
1978
+ * @param options - The response key name configuration (dot-notation paths supported)
1979
+ * @returns A typed PaginatedCollection instance
1634
1980
  */
1635
- readonly capabilities: IStrategyCapabilities;
1981
+ paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
1636
1982
  /**
1637
- * Emit only the pagination params; filters/sorts/etc. are ignored
1983
+ * Derive the current page number from the `hydra:view` `@id` URL
1638
1984
  *
1639
- * @param state - The current query builder state
1640
- * @param options - The query parameter key name configuration
1641
- * @returns The two pagination query-string fragments
1985
+ * Reads the `page` query param; a missing view (pagination disabled
1986
+ * or a single-page collection without a partial view) or a link
1987
+ * without the param resolves to page 1.
1988
+ *
1989
+ * @param viewUrl - The `hydra:view.@id` URL, or null
1990
+ * @returns The current page number
1642
1991
  */
1643
- protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
1644
- }
1645
-
1646
- /**
1647
- * Base class for response strategies whose pagination metadata is a flat
1648
- * key-value envelope on the response body
1649
- *
1650
- * Laravel's stock pagination and Spatie's `QueryBuilder` both emit the
1651
- * same flat shape — `{ data, current_page, total, per_page, from, to,
1652
- * next_page_url, prev_page_url, first_page_url, last_page, last_page_url
1653
- * }` — and both response strategies were duplicating the byte-identical
1654
- * `new PaginatedCollection(response[options.X], ...)` body before this
1655
- * base existed. Concrete classes now extend and provide only the
1656
- * docstring describing their driver's specific shape (see
1657
- * `LaravelResponseStrategy`, `SpatieResponseStrategy`).
1658
- *
1659
- * Drivers whose pagination metadata is a nested envelope (JSON:API,
1660
- * NestJS, Strapi) extend `AbstractDotPathResponseStrategy` instead.
1661
- * Drivers whose metadata comes from HTTP headers (PostgREST) or is
1662
- * derived from response URLs (DRF) implement `IResponseStrategy`
1663
- * directly.
1664
- */
1665
- declare abstract class AbstractFlatResponseStrategy implements IResponseStrategy {
1992
+ private _deriveCurrentPage;
1666
1993
  /**
1667
- * Parse a flat-envelope pagination response into a PaginatedCollection
1994
+ * Derive the last page number
1668
1995
  *
1669
- * @param response - The raw API response object
1670
- * @param options - The response key name configuration
1671
- * @returns A typed PaginatedCollection instance
1996
+ * Resolution order: the `page` param of `hydra:last`, then
1997
+ * `ceil(total ÷ perPage)`, then 1 for a view-less response that
1998
+ * provably holds the entire non-empty collection.
1999
+ *
2000
+ * @param lastPageUrl - The `hydra:view.hydra:last` URL (may be undefined)
2001
+ * @param viewUrl - The `hydra:view.@id` URL, or null
2002
+ * @param data - The items on the current page
2003
+ * @param total - The total item count
2004
+ * @param perPage - The page size
2005
+ * @returns The last page number, or undefined when inputs insufficient
1672
2006
  */
1673
- paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
2007
+ private _deriveLastPage;
2008
+ /**
2009
+ * Derive `perPage` from the `hydra:view` `@id` URL
2010
+ *
2011
+ * Reads the `itemsPerPage` query param (echoed whenever the request
2012
+ * set it). When absent, a page with a `hydra:next` successor is
2013
+ * necessarily full, so its item count equals the page size.
2014
+ *
2015
+ * @param viewUrl - The `hydra:view.@id` URL, or null
2016
+ * @param nextPageUrl - The `hydra:view.hydra:next` URL (may be undefined)
2017
+ * @param data - The items on the current page
2018
+ * @returns The page size, or undefined
2019
+ */
2020
+ private _derivePerPage;
2021
+ /**
2022
+ * Extract an integer query parameter from a Hydra URL
2023
+ *
2024
+ * @param url - The URL to parse
2025
+ * @param name - The query-parameter name to look up (e.g. `page`)
2026
+ * @returns The integer value, or undefined
2027
+ */
2028
+ private _extractNumberParam;
2029
+ /**
2030
+ * Extract a single query parameter from a URL via the WHATWG URL parser
2031
+ *
2032
+ * Hydra links are typically **relative** (`/books?page=4`), so parsing
2033
+ * retries against a placeholder base before giving up. Returns
2034
+ * undefined when the URL is unparseable or the parameter is absent.
2035
+ *
2036
+ * @param url - The URL to parse
2037
+ * @param name - The query-parameter name to look up
2038
+ * @returns The raw string value of the parameter, or undefined
2039
+ */
2040
+ private _extractQueryParam;
2041
+ /**
2042
+ * Derive `from` for a view-less response holding the whole collection
2043
+ *
2044
+ * @param viewUrl - The `hydra:view.@id` URL, or null
2045
+ * @param data - The items on the current page
2046
+ * @param total - The total item count
2047
+ * @returns 1 when the response provably holds all items, undefined otherwise
2048
+ */
2049
+ private _wholeSetFrom;
2050
+ /**
2051
+ * Derive `to` for a view-less response holding the whole collection
2052
+ *
2053
+ * @param viewUrl - The `hydra:view.@id` URL, or null
2054
+ * @param data - The items on the current page
2055
+ * @param total - The total item count
2056
+ * @returns The item count when the response provably holds all items, undefined otherwise
2057
+ */
2058
+ private _wholeSetTo;
1674
2059
  }
1675
2060
 
1676
2061
  /**
1677
- * Response strategy for the Laravel (pagination-only) driver
2062
+ * Request strategy for the Directus driver
1678
2063
  *
1679
- * Parses flat Laravel pagination responses:
1680
- * ```json
1681
- * {
1682
- * "data": [...],
1683
- * "current_page": 1,
1684
- * "total": 100,
1685
- * "per_page": 15,
1686
- * "from": 1,
1687
- * "to": 15,
1688
- * "next_page_url": "...",
1689
- * "prev_page_url": "...",
1690
- * "first_page_url": "...",
1691
- * "last_page": 7,
1692
- * "last_page_url": "..."
1693
- * }
1694
- * ```
2064
+ * Generates URIs in [Directus' query format](https://docs.directus.io/reference/query.html):
2065
+ * - Filters: `filter[field][_eq]=value` (multi-value collapses to `_in`)
2066
+ * - Operator filters: `filter[field][_op]=value` (translated from
2067
+ * `FilterOperatorEnum` — `BTW`→`_between`, `SW`→`_starts_with`,
2068
+ * `ILIKE`→`_icontains`, `NOT`→`_neq`/`_nin`, `NULL`→`_null`/`_nnull`)
2069
+ * - Sorts: `sort=-created_at,name` (CSV, `-` prefix = DESC)
2070
+ * - Field selection / relations: a single `fields=` CSV — flat columns
2071
+ * from `addSelect`, whole relations from `addIncludes` (`rel.*`), and
2072
+ * column-projected relations from `addEmbedded` (`rel.col1,rel.col2`)
2073
+ * - Search: `search=term` (global full-text search)
2074
+ * - Metadata: a constant `meta=total_count,filter_count` so responses
2075
+ * carry the totals the response strategy needs
2076
+ * - Pagination (page-based): `limit=N&page=N`
1695
2077
  *
1696
- * The traversal algorithm (flat `response[options.X]` lookups) is
1697
- * inherited from `AbstractFlatResponseStrategy`; this class exists so
1698
- * `DriverEnum.LARAVEL` resolves to a distinct identity at the DI layer
1699
- * even though the parsing logic is shared with Spatie.
1700
- */
1701
- declare class LaravelResponseStrategy extends AbstractFlatResponseStrategy {
1702
- }
1703
-
1704
- /**
1705
- * Request strategy for the NestJS (nestjs-paginate) driver
2078
+ * The `filter` / `sort` / `fields` / `search` / `limit` / `page` keys
2079
+ * honour the existing `QueryBuilderOptions` names (their defaults match
2080
+ * the Directus wire format); `meta` is fixed by the server and lives as
2081
+ * a private static. Directus' `deep[...]` relational query options and
2082
+ * nested relation filtering are out of scope.
1706
2083
  *
1707
- * Generates URIs in the NestJS paginate format:
1708
- * - Simple filters: `filter.field=value`
1709
- * - Operator filters: `filter.field=$operator:value`
1710
- * - Sorts: `sortBy=field1:DESC,field2:ASC`
1711
- * - Select: `select=col1,col2`
1712
- * - Search: `search=term`
1713
- * - Pagination: `limit=N&page=N`
2084
+ * PostgREST-native full-text search operators (`FTS`, `PHFTS`, `PLFTS`,
2085
+ * `WFTS`) throw `UnsupportedFilterOperatorError` — use `search` or the
2086
+ * `CONTAINS` / `ILIKE` operator filters instead.
1714
2087
  *
1715
- * @see https://github.com/ppetzold/nestjs-paginate
2088
+ * @see https://docs.directus.io/reference/query.html
2089
+ * @see https://docs.directus.io/reference/filter-rules.html
1716
2090
  */
1717
- declare class NestjsRequestStrategy extends AbstractRequestStrategy {
2091
+ declare class DirectusRequestStrategy extends AbstractRequestStrategy {
1718
2092
  /**
1719
- * Filters, operator filters, sorts, flat select, global search — no
1720
- * per-model fields, no includes
2093
+ * Filters, operator filters, sorts, flat select, includes and embedded
2094
+ * (both folding into `fields=`), global search — no per-model fields
2095
+ * (Directus scopes relational projections with dot paths, not a
2096
+ * `fields[model]` map)
1721
2097
  */
1722
2098
  readonly capabilities: IStrategyCapabilities;
1723
2099
  /**
1724
- * Validate that the given limit is accepted by nestjs-paginate
1725
- *
1726
- * Accepts any integer `>= 1` as a page size, plus `-1` which nestjs-paginate
1727
- * interprets as "fetch all items" (server must opt-in via `maxLimit: -1`).
2100
+ * Directus-native name of the metadata query key
1728
2101
  *
1729
- * @param limit - The limit value to validate
1730
- * @throws {InvalidLimitError} If the value is not an integer, or is 0, or is a negative number other than -1
2102
+ * `meta` has no `QueryBuilderOptions` slot and is fixed by the server,
2103
+ * so it lives as a private static to be visible in one place.
1731
2104
  */
1732
- validateLimit(limit: number): void;
2105
+ private static readonly _metaKey;
1733
2106
  /**
1734
- * Emit NestJS-format query-string segments in canonical order:
1735
- * filtersoperator filters sortByselectsearch → limit → page
2107
+ * Emit Directus-format query-string segments in canonical order:
2108
+ * filter (merged) sortfieldssearchmeta → limit → page
2109
+ *
2110
+ * Simple filters and operator filters share a single `filter` wrapper
2111
+ * so qs emits one ordered, deeply-nested bracket structure rather than
2112
+ * two duplicate top-level `filter[...]` blocks.
1736
2113
  *
1737
2114
  * @param state - The current query builder state
1738
2115
  * @param options - The query parameter key name configuration
@@ -1740,7 +2117,31 @@ declare class NestjsRequestStrategy extends AbstractRequestStrategy {
1740
2117
  */
1741
2118
  protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
1742
2119
  /**
1743
- * Append simple filter parameters as `filter.field=value1,value2`
2120
+ * Append the single `fields=` CSV combining flat columns, whole
2121
+ * relations, and column-projected relations
2122
+ *
2123
+ * Flat columns come from `addSelect`; relations from `addIncludes`
2124
+ * emit as `rel.*`; embedded relations from `addEmbedded` emit one
2125
+ * `rel.col` entry per column (or `rel.*` when no columns were given).
2126
+ * A relation present in both folds into the embedded fragment, which
2127
+ * carries the column information. When relations are present but no
2128
+ * flat columns were selected, the flat part defaults to `*` so the
2129
+ * base item's columns are not silently dropped from the projection.
2130
+ *
2131
+ * @param state - The current query builder state
2132
+ * @param options - The query parameter key name configuration
2133
+ * @param out - The accumulator the caller joins into the URI
2134
+ */
2135
+ private _appendFields;
2136
+ /**
2137
+ * Append the unified `filter[...]` wrapper combining simple filters
2138
+ * and operator filters
2139
+ *
2140
+ * Both kinds emit into the same nested object under the filter key so
2141
+ * qs produces a single deeply-bracketed block per request. Simple
2142
+ * single-value filters fold to `_eq`; simple multi-value filters fold
2143
+ * to `_in` (CSV). Operator filters then merge into the same per-field
2144
+ * map, potentially co-existing with a simple filter on the same field.
1744
2145
  *
1745
2146
  * @param state - The current query builder state
1746
2147
  * @param options - The query parameter key name configuration
@@ -1756,25 +2157,26 @@ declare class NestjsRequestStrategy extends AbstractRequestStrategy {
1756
2157
  */
1757
2158
  private _appendLimit;
1758
2159
  /**
1759
- * Append operator-filter parameters as `filter.field=$op:value`
2160
+ * Append the constant `meta=total_count,filter_count` parameter
1760
2161
  *
1761
- * Groups by field; multi-value operators ($in, $btw) join values with commas.
2162
+ * Always emitted: the Directus response strategy reads the totals from
2163
+ * `meta`, which the server only includes when the request asks for it.
1762
2164
  *
1763
- * @param state - The current query builder state
1764
- * @param options - The query parameter key name configuration
1765
2165
  * @param out - The accumulator the caller joins into the URI
1766
2166
  */
1767
- private _appendOperatorFilters;
2167
+ private _appendMeta;
1768
2168
  /**
1769
2169
  * Append the page parameter
1770
2170
  *
2171
+ * Directus pages are 1-indexed, matching the library state directly.
2172
+ *
1771
2173
  * @param state - The current query builder state
1772
2174
  * @param options - The query parameter key name configuration
1773
2175
  * @param out - The accumulator the caller joins into the URI
1774
2176
  */
1775
2177
  private _appendPage;
1776
2178
  /**
1777
- * Append the search parameter as `search=term`
2179
+ * Append the `search=` global full-text search parameter
1778
2180
  *
1779
2181
  * @param state - The current query builder state
1780
2182
  * @param options - The query parameter key name configuration
@@ -1782,55 +2184,1954 @@ declare class NestjsRequestStrategy extends AbstractRequestStrategy {
1782
2184
  */
1783
2185
  private _appendSearch;
1784
2186
  /**
1785
- * Append the select parameter as `select=col1,col2`
2187
+ * Append the `sort=-created_at,name` CSV parameter
1786
2188
  *
1787
2189
  * @param state - The current query builder state
1788
2190
  * @param options - The query parameter key name configuration
1789
2191
  * @param out - The accumulator the caller joins into the URI
1790
2192
  */
1791
- private _appendSelect;
2193
+ private _appendSort;
1792
2194
  /**
1793
- * Append sort parameter as `sortBy=field1:DESC,field2:ASC`
2195
+ * Translate a `FilterOperatorEnum` operator filter into Directus'
2196
+ * `_operator → value` payload shape
2197
+ *
2198
+ * The mapping is library-canonical → Directus-native:
2199
+ * - `EQ`/`GT`/`GTE`/`LT`/`LTE` → `_eq`/`_gt`/`_gte`/`_lt`/`_lte`
2200
+ * - `CONTAINS` → `_contains`; `ILIKE` → `_icontains` (case-insensitive)
2201
+ * - `SW` → `_starts_with`
2202
+ * - `IN` → `_in` (CSV)
2203
+ * - `BTW` → `_between` with `min,max` (arity-checked)
2204
+ * - `NOT` → `_neq` (single value) / `_nin` (multi-value, CSV)
2205
+ * - `NULL` → `_null=true` (when value is `true`) / `_nnull=true` (when
2206
+ * value is `false`); arity- and type-checked
2207
+ *
2208
+ * PostgREST's full-text-search operators (`FTS`, `PHFTS`, `PLFTS`,
2209
+ * `WFTS`) have no Directus equivalent and throw
2210
+ * `UnsupportedFilterOperatorError`.
2211
+ *
2212
+ * @param filter - The operator filter to translate
2213
+ * @returns A `{ _operator: value }` payload ready to merge under
2214
+ * `filter[field]`
2215
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
2216
+ * exactly two values, or `NULL` does not receive exactly one boolean
2217
+ * @throws {UnsupportedFilterOperatorError} If the operator is a
2218
+ * PostgREST-only FTS variant
2219
+ */
2220
+ private _formatOperatorPayload;
2221
+ }
2222
+
2223
+ /**
2224
+ * Response strategy for the Directus driver
2225
+ *
2226
+ * Parses Directus collection responses (with `meta=total_count,filter_count`
2227
+ * requested, which the request strategy always does):
2228
+ *
2229
+ * ```json
2230
+ * {
2231
+ * "data": [{ "id": 1, "title": "Hello" }],
2232
+ * "meta": { "total_count": 48, "filter_count": 12 }
2233
+ * }
2234
+ * ```
2235
+ *
2236
+ * The default `total` path is `meta.filter_count` — the number of items
2237
+ * matching the current filter, which is the relevant total for paging a
2238
+ * filtered collection (`meta.total_count` ignores filters; point the
2239
+ * `total` path at it via `IPaginationConfig` if that is what you want).
2240
+ *
2241
+ * The envelope carries **no current-page or page-size field**, so:
2242
+ *
2243
+ * - `currentPage` falls back to **1** unless a `currentPage` path is
2244
+ * configured and resolves (only guaranteed correct for single-page
2245
+ * results — track the requested page in your own state for multi-page
2246
+ * UIs).
2247
+ * - `perPage` resolves only when a `perPage` path is configured.
2248
+ * - `lastPage` is `ceil(total ÷ perPage)` when both are known; on a
2249
+ * response that provably holds the whole filtered set it resolves
2250
+ * to 1.
2251
+ *
2252
+ * Every key path is overridable via `IPaginationConfig` (dot notation
2253
+ * supported), so custom wrappers that do include paging fields map
2254
+ * without subclassing.
2255
+ *
2256
+ * @see https://docs.directus.io/reference/query.html#meta
2257
+ */
2258
+ declare class DirectusResponseStrategy extends AbstractDotPathResponseStrategy {
2259
+ /**
2260
+ * Parse a Directus collection response into a PaginatedCollection
2261
+ *
2262
+ * @param response - The raw API response body
2263
+ * @param options - The response key name configuration (dot-notation paths supported)
2264
+ * @returns A typed PaginatedCollection instance
2265
+ */
2266
+ paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
2267
+ /**
2268
+ * Derive the last page number
2269
+ *
2270
+ * Resolution order: the configured `lastPage` path, then
2271
+ * `ceil(total ÷ perPage)` when both are known, then 1 when the
2272
+ * response provably holds the entire non-empty filtered set.
2273
+ *
2274
+ * @param response - The raw response object
2275
+ * @param options - The response key name configuration
2276
+ * @param data - The items on the current page
2277
+ * @param total - The total item count
2278
+ * @param perPage - The page size
2279
+ * @returns The last page number, or undefined when inputs insufficient
2280
+ */
2281
+ private _deriveLastPage;
2282
+ /**
2283
+ * Derive `from` for a response that holds the whole filtered set
2284
+ *
2285
+ * @param data - The items on the current page
2286
+ * @param total - The total item count
2287
+ * @returns 1 when the page provably holds all items, undefined otherwise
2288
+ */
2289
+ private _singlePageFrom;
2290
+ /**
2291
+ * Derive `to` for a response that holds the whole filtered set
2292
+ *
2293
+ * @param data - The items on the current page
2294
+ * @param total - The total item count
2295
+ * @returns The item count when the page provably holds all items, undefined otherwise
2296
+ */
2297
+ private _singlePageTo;
2298
+ }
2299
+
2300
+ /**
2301
+ * Request strategy for the Django REST Framework (DRF) driver
2302
+ *
2303
+ * Generates URIs in DRF's flat query-parameter format, augmented by
2304
+ * django-filter's double-underscore lookup convention:
2305
+ *
2306
+ * - Simple filters: `field=value` (multi-value collapses to `field__in=v1,v2`)
2307
+ * - Operator filters: `field__lookup=value` (translated from
2308
+ * `FilterOperatorEnum` — `GTE`→`__gte`, `ILIKE`→`__icontains`,
2309
+ * `BTW`→`__range`, `NULL`→`__isnull`, etc.)
2310
+ * - Ordering: `ordering=-field1,field2` (`-` prefix = DESC)
2311
+ * - Search: `search=term` (DRF's SearchFilter)
2312
+ * - Pagination: `page=N&page_size=M` (PageNumberPagination)
2313
+ *
2314
+ * `ordering` and `page_size` are DRF-idiomatic param names and are
2315
+ * intentionally not configurable via `QueryBuilderOptions` — same
2316
+ * precedent as PostgREST's `order` and `offset`. PostgREST's full-text
2317
+ * search operators (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) and the generic
2318
+ * `NOT` have no django-filter equivalent and throw
2319
+ * `UnsupportedFilterOperatorError`.
2320
+ *
2321
+ * @see https://www.django-rest-framework.org/api-guide/filtering/
2322
+ * @see https://django-filter.readthedocs.io/
2323
+ */
2324
+ declare class DrfRequestStrategy extends AbstractRequestStrategy {
2325
+ /**
2326
+ * Simple filters, operator filters (django-filter lookups), sorts, and
2327
+ * global search — no per-model fields, no relation includes, no flat
2328
+ * select (django-restql adds it but is not core DRF)
2329
+ */
2330
+ readonly capabilities: IStrategyCapabilities;
2331
+ /**
2332
+ * DRF-native names of the three hardcoded query keys
2333
+ *
2334
+ * `ordering` and `page_size` are DRF/django-filter conventions and are
2335
+ * intentionally not configurable through `QueryBuilderOptions`. `page`
2336
+ * matches the default `QueryBuilderOptions.page`, and `search` matches
2337
+ * the default `QueryBuilderOptions.search`, so those flow through the
2338
+ * shared options object.
2339
+ */
2340
+ private static readonly _orderingKey;
2341
+ private static readonly _pageSizeKey;
2342
+ /**
2343
+ * Emit DRF-format query-string segments in canonical order:
2344
+ * filters → operator filters → ordering → search → pagination
2345
+ *
2346
+ * @param state - The current query builder state
2347
+ * @param options - The query parameter key name configuration
2348
+ * @returns Ordered query-string fragments
2349
+ */
2350
+ protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
2351
+ /**
2352
+ * Append simple filter parameters
2353
+ *
2354
+ * Single-value filters emit `field=value` (django-filter's default
2355
+ * exact match). Multi-value filters collapse to django-filter's
2356
+ * `field__in=v1,v2,v3` form, which is the idiomatic way to express
2357
+ * "value in list" in DRF.
2358
+ *
2359
+ * @param state - The current query builder state
2360
+ * @param out - The accumulator the caller joins into the URI
2361
+ */
2362
+ private _appendFilters;
2363
+ /**
2364
+ * Append operator-filter parameters as `field__lookup=value`
2365
+ *
2366
+ * Maps each `FilterOperatorEnum` value to a django-filter lookup
2367
+ * suffix. `BTW` expands to `field__range=min,max`; `NULL` emits
2368
+ * `field__isnull=true|false`; the generic `NOT` and PostgREST-only
2369
+ * FTS operators are unsupported.
2370
+ *
2371
+ * @param state - The current query builder state
2372
+ * @param out - The accumulator the caller joins into the URI
2373
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
2374
+ * exactly two values, or `NULL` does not receive exactly one boolean
2375
+ * @throws {UnsupportedFilterOperatorError} If the operator has no
2376
+ * django-filter equivalent
2377
+ */
2378
+ private _appendOperatorFilters;
2379
+ /**
2380
+ * Append `ordering=-field1,field2` (django's `-` prefix = DESC)
2381
+ *
2382
+ * @param state - The current query builder state
2383
+ * @param out - The accumulator the caller joins into the URI
2384
+ */
2385
+ private _appendOrdering;
2386
+ /**
2387
+ * Append `page=N&page_size=M`
2388
+ *
2389
+ * `page` follows `options.page` (default `page`, matching DRF); the
2390
+ * size key is hardcoded to DRF's idiomatic `page_size`.
2391
+ *
2392
+ * @param state - The current query builder state
2393
+ * @param options - The query parameter key name configuration
2394
+ * @param out - The accumulator the caller joins into the URI
2395
+ */
2396
+ private _appendPagination;
2397
+ /**
2398
+ * Append `search=term` when a search term is set
1794
2399
  *
1795
2400
  * @param state - The current query builder state
1796
2401
  * @param options - The query parameter key name configuration
1797
2402
  * @param out - The accumulator the caller joins into the URI
1798
2403
  */
2404
+ private _appendSearch;
2405
+ /**
2406
+ * Translate a `FilterOperatorEnum` operator filter into a
2407
+ * `[suffix, serializedValue]` pair
2408
+ *
2409
+ * The suffix is appended to the field name with a `__` separator on the
2410
+ * wire side (`field__gte=18`). The empty string means "no suffix" —
2411
+ * django-filter's implicit `exact` lookup.
2412
+ *
2413
+ * Mapping:
2414
+ * - `EQ` → `''` (no suffix; default exact match)
2415
+ * - `GT`/`GTE`/`LT`/`LTE`/`CONTAINS` → identity (lowercased name)
2416
+ * - `ILIKE` → `icontains` (closest case-insensitive analog)
2417
+ * - `IN` → `in` with comma-joined values
2418
+ * - `SW` → `startswith`
2419
+ * - `BTW` → `range` with comma-joined `[min, max]` (arity-checked)
2420
+ * - `NULL` → `isnull` with boolean value (arity- and type-checked)
2421
+ * - `NOT` → `UnsupportedFilterOperatorError` (no generic negation in
2422
+ * django-filter; use `__exclude` on the queryset instead)
2423
+ * - `FTS`/`PLFTS`/`PHFTS`/`WFTS` → `UnsupportedFilterOperatorError`
2424
+ *
2425
+ * @param filter - The operator filter to translate
2426
+ * @returns A `[lookupSuffix, serializedValue]` tuple
2427
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
2428
+ * exactly two values, or `NULL` does not receive exactly one boolean
2429
+ * @throws {UnsupportedFilterOperatorError} If the operator has no
2430
+ * django-filter equivalent
2431
+ */
2432
+ private _formatOperatorPayload;
2433
+ }
2434
+
2435
+ /**
2436
+ * Response strategy for the Django REST Framework (DRF) driver
2437
+ *
2438
+ * Parses DRF `PageNumberPagination` responses:
2439
+ *
2440
+ * ```json
2441
+ * {
2442
+ * "count": 100,
2443
+ * "next": "http://api.example.com/items/?page=3",
2444
+ * "previous": "http://api.example.com/items/?page=1",
2445
+ * "results": [...]
2446
+ * }
2447
+ * ```
2448
+ *
2449
+ * DRF emits no `current_page` field in the body, so this strategy
2450
+ * **derives** the current page (and the page size) by inspecting the
2451
+ * `next` / `previous` URLs:
2452
+ *
2453
+ * - `previous === null` → current page is **1**.
2454
+ * - `previous` set but has no `?page=N` param → DRF omits `page=1` from
2455
+ * URLs when the previous page is the first, so we infer **2**.
2456
+ * - `previous` has `?page=N` → current page is **N + 1**.
2457
+ *
2458
+ * Similarly, `perPage` is parsed from any `?page_size=N` query param on
2459
+ * `next` or `previous`, and `lastPage` is computed as
2460
+ * `ceil(count / perPage)`. When `perPage` cannot be discovered (e.g. on a
2461
+ * single-page response that emits both URLs as `null`), `perPage` and
2462
+ * `lastPage` are left undefined.
2463
+ *
2464
+ * Key paths are resolved through `DrfResponseOptions`, which defaults
2465
+ * `data → 'results'`, `total → 'count'`, `nextPageUrl → 'next'`,
2466
+ * `prevPageUrl → 'previous'`. The current-page / per-page / last-page
2467
+ * paths default to empty strings — the strategy ignores `options` for
2468
+ * those slots and uses URL inspection instead.
2469
+ *
2470
+ * @see https://www.django-rest-framework.org/api-guide/pagination/#pagenumberpagination
2471
+ */
2472
+ declare class DrfResponseStrategy implements IResponseStrategy {
2473
+ /**
2474
+ * Parse a DRF pagination response into a PaginatedCollection
2475
+ *
2476
+ * @param response - The raw API response body
2477
+ * @param options - The response key name configuration
2478
+ * @returns A typed PaginatedCollection instance
2479
+ */
2480
+ paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
2481
+ /**
2482
+ * Derive the current page number from the `previous` URL
2483
+ *
2484
+ * - `null` → page 1
2485
+ * - URL without `?page=N` → page 2 (DRF omits `page=1` from URLs)
2486
+ * - URL with `?page=N` → N + 1
2487
+ *
2488
+ * @param prevPageUrl - The `previous` link from the DRF response, or null
2489
+ * @returns The current page number
2490
+ */
2491
+ private _deriveCurrentPage;
2492
+ /**
2493
+ * Derive `from` as the 1-indexed offset of the first item on this page
2494
+ *
2495
+ * @param currentPage - The current page number
2496
+ * @param perPage - The page size (may be undefined)
2497
+ * @returns The 1-indexed `from` index, or undefined when perPage is unknown
2498
+ */
2499
+ private _deriveFrom;
2500
+ /**
2501
+ * Derive the last page number as `ceil(total / perPage)`
2502
+ *
2503
+ * Both inputs must be defined; an empty result set (`total === 0`)
2504
+ * yields `lastPage = 0` which the caller treats as "no useful info"
2505
+ * and skips the sync to `NestService.lastPage`.
2506
+ *
2507
+ * @param total - The total item count
2508
+ * @param perPage - The page size
2509
+ * @returns The last page number, or undefined when either input is missing
2510
+ */
2511
+ private _deriveLastPage;
2512
+ /**
2513
+ * Derive `perPage` by parsing `?page_size=N` from any available URL
2514
+ *
2515
+ * Tries `next` first (page 1 always has a `next` URL with `page_size`
2516
+ * if any non-default size was requested), then falls back to
2517
+ * `previous`. Returns undefined when neither URL contains the param —
2518
+ * the consumer is then on a single-page result with the server's
2519
+ * default page size, which is not introspectable from the body alone.
2520
+ *
2521
+ * @param nextPageUrl - The `next` link from the response, or null
2522
+ * @param prevPageUrl - The `previous` link from the response, or null
2523
+ * @returns The page size, or undefined
2524
+ */
2525
+ private _derivePerPage;
2526
+ /**
2527
+ * Derive `to` as the 1-indexed offset of the last item on this page
2528
+ *
2529
+ * Clamped to `total` so the last page does not report past the end.
2530
+ *
2531
+ * @param currentPage - The current page number
2532
+ * @param perPage - The page size (may be undefined)
2533
+ * @param total - The total item count (may be undefined)
2534
+ * @returns The 1-indexed `to` index, or undefined when inputs insufficient
2535
+ */
2536
+ private _deriveTo;
2537
+ /**
2538
+ * Extract the `page` query parameter from a DRF pagination URL
2539
+ *
2540
+ * Returns the integer value of `?page=N`, or undefined when the URL is
2541
+ * malformed or has no `page` param (which, by DRF convention, means
2542
+ * page 1 — the caller infers the semantics).
2543
+ *
2544
+ * @param url - The URL to parse
2545
+ * @returns The integer page value, or undefined
2546
+ */
2547
+ private _extractPageParam;
2548
+ /**
2549
+ * Extract the `page_size` query parameter from a DRF pagination URL
2550
+ *
2551
+ * @param url - The URL to parse (or null)
2552
+ * @returns The integer page-size value, or undefined
2553
+ */
2554
+ private _extractPageSizeParam;
2555
+ /**
2556
+ * Extract a single query parameter from a URL via the WHATWG URL parser
2557
+ *
2558
+ * Returns undefined when the URL is unparseable (relative URL without a
2559
+ * base, or malformed) or when the parameter is absent.
2560
+ *
2561
+ * @param url - The URL to parse
2562
+ * @param name - The query-parameter name to look up
2563
+ * @returns The raw string value of the parameter, or undefined
2564
+ */
2565
+ private _extractQueryParam;
2566
+ }
2567
+
2568
+ /**
2569
+ * Request strategy for the FeathersJS driver
2570
+ *
2571
+ * Generates URIs in [Feathers' common database adapter query syntax](https://feathersjs.com/api/databases/querying):
2572
+ * - Filters: `field=value` (exact match); multi-value folds to `$in`
2573
+ * (`field[$in][0]=v1&field[$in][1]=v2`)
2574
+ * - Operator filters: `field[$op]=value` (translated from
2575
+ * `FilterOperatorEnum` — `BTW`→`$gte`+`$lte` pair, `NOT`→`$ne`/`$nin`)
2576
+ * - Sorts: `$sort[field]=1` (ASC) / `$sort[field]=-1` (DESC)
2577
+ * - Flat field selection: `$select[0]=col1&$select[1]=col2`
2578
+ * - Pagination (offset-based): `$limit=N&$skip=M` with
2579
+ * `skip = (page - 1) × limit`
2580
+ *
2581
+ * The dollar-prefixed query keys (`$limit`, `$skip`, `$sort`, `$select`)
2582
+ * are fixed by the Feathers adapter-commons parser and intentionally not
2583
+ * configurable through `QueryBuilderOptions`; they live as private
2584
+ * statics so they are visible in one place.
2585
+ *
2586
+ * Feathers' core adapter syntax has no relation includes, no per-model
2587
+ * field selection, and no global search — the corresponding fluent
2588
+ * methods throw the matching `Unsupported*Error`. `CONTAINS` / `ILIKE` /
2589
+ * `SW` (LIKE-style matching is adapter-specific, not core), `NULL` (no
2590
+ * null-check operator on the wire), and the PostgREST-native full-text
2591
+ * operators (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
2592
+ * `UnsupportedFilterOperatorError`.
2593
+ *
2594
+ * @see https://feathersjs.com/api/databases/querying
2595
+ */
2596
+ declare class FeathersRequestStrategy extends AbstractRequestStrategy {
2597
+ /**
2598
+ * Filters, operator filters, sorts, flat field selection (`select`) —
2599
+ * no per-model fields, no includes, no global search, no embedded
2600
+ * resources
2601
+ */
2602
+ readonly capabilities: IStrategyCapabilities;
2603
+ /**
2604
+ * Feathers-native names of the four hardcoded query keys
2605
+ *
2606
+ * The dollar prefix marks adapter-commons system params apart from
2607
+ * filter fields; these keys are fixed by the server and intentionally
2608
+ * not configurable through `QueryBuilderOptions`.
2609
+ */
2610
+ private static readonly _limitKey;
2611
+ private static readonly _selectKey;
2612
+ private static readonly _skipKey;
2613
+ private static readonly _sortKey;
2614
+ /**
2615
+ * Emit Feathers-format query-string segments in canonical order:
2616
+ * filters → operator filters → $sort → $select → $limit → $skip
2617
+ *
2618
+ * @param state - The current query builder state
2619
+ * @param _options - The query parameter key name configuration (unused;
2620
+ * Feathers' system keys are fixed by the server)
2621
+ * @returns Ordered query-string fragments
2622
+ */
2623
+ protected parts(state: IQueryBuilderState, _options: QueryBuilderOptions): string[];
2624
+ /**
2625
+ * Append simple filter parameters
2626
+ *
2627
+ * A single value emits the bare exact-match form (`field=value`);
2628
+ * multiple values fold to the `$in` list
2629
+ * (`field[$in][0]=v1&field[$in][1]=v2`).
2630
+ *
2631
+ * @param state - The current query builder state
2632
+ * @param out - The accumulator the caller joins into the URI
2633
+ */
2634
+ private _appendFilters;
2635
+ /**
2636
+ * Append explicit operator filters in the `field[$op]=value` syntax
2637
+ *
2638
+ * @param state - The current query builder state
2639
+ * @param out - The accumulator the caller joins into the URI
2640
+ */
2641
+ private _appendOperatorFilters;
2642
+ /**
2643
+ * Append the `$limit` / `$skip` pagination pair
2644
+ *
2645
+ * Feathers paginates by offset, so the 1-based page number from state
2646
+ * converts to `skip = (page - 1) × limit`.
2647
+ *
2648
+ * @param state - The current query builder state
2649
+ * @param out - The accumulator the caller joins into the URI
2650
+ */
2651
+ private _appendPagination;
2652
+ /**
2653
+ * Append the `$select[0]=col1&$select[1]=col2` array from the flat
2654
+ * select state
2655
+ *
2656
+ * @param state - The current query builder state
2657
+ * @param out - The accumulator the caller joins into the URI
2658
+ */
2659
+ private _appendSelect;
2660
+ /**
2661
+ * Append the `$sort[field]=1|-1` map
2662
+ *
2663
+ * @param state - The current query builder state
2664
+ * @param out - The accumulator the caller joins into the URI
2665
+ */
1799
2666
  private _appendSort;
2667
+ /**
2668
+ * Translate a `FilterOperatorEnum` operator filter into Feathers'
2669
+ * `$operator → value` payload shape (or a bare primitive for `EQ`)
2670
+ *
2671
+ * The mapping is library-canonical → Feathers-native:
2672
+ * - `EQ` → bare `field=value` (no operator wrapper)
2673
+ * - `GT`/`GTE`/`LT`/`LTE` → `$gt` / `$gte` / `$lt` / `$lte`
2674
+ * - `IN` → `$in` (array)
2675
+ * - `BTW` → `$gte` + `$lte` pair in one payload (arity-checked)
2676
+ * - `NOT` → `$ne` (single value) / `$nin` (multi-value)
2677
+ *
2678
+ * `CONTAINS`, `ILIKE`, and `SW` (LIKE-style matching is
2679
+ * adapter-specific in Feathers, not part of the common syntax),
2680
+ * `NULL` (no null-check operator), and PostgREST's full-text-search
2681
+ * operators (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
2682
+ * `UnsupportedFilterOperatorError`.
2683
+ *
2684
+ * @param filter - The operator filter to translate
2685
+ * @returns A `{ $operator: value }` payload ready to nest under
2686
+ * `field[...]`, or a bare primitive for `EQ`
2687
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
2688
+ * exactly two values
2689
+ * @throws {UnsupportedFilterOperatorError} If the operator has no
2690
+ * Feathers equivalent
2691
+ */
2692
+ private _formatOperatorPayload;
1800
2693
  }
1801
2694
 
1802
2695
  /**
1803
- * Response strategy for the NestJS (nestjs-paginate) driver
2696
+ * Response strategy for the FeathersJS driver
2697
+ *
2698
+ * Parses the paginated envelope emitted by Feathers database adapters:
1804
2699
  *
1805
- * Parses nested NestJS pagination responses:
1806
2700
  * ```json
1807
2701
  * {
1808
- * "data": [...],
1809
- * "meta": {
1810
- * "currentPage": 1,
1811
- * "totalItems": 100,
1812
- * "itemsPerPage": 10,
1813
- * "totalPages": 10
1814
- * },
1815
- * "links": {
1816
- * "first": "url",
1817
- * "previous": "url",
1818
- * "next": "url",
1819
- * "last": "url",
1820
- * "current": "url"
1821
- * }
2702
+ * "total": 48,
2703
+ * "limit": 10,
2704
+ * "skip": 10,
2705
+ * "data": [...]
2706
+ * }
2707
+ * ```
2708
+ *
2709
+ * The envelope is offset-based — no page number, no navigation URLs —
2710
+ * so position derives arithmetically:
2711
+ *
2712
+ * - `currentPage` is `skip / limit + 1` (integer division; a zero or
2713
+ * missing `limit` falls back to page **1**).
2714
+ * - `perPage` comes straight from `limit`; `lastPage` is
2715
+ * `ceil(total / limit)`.
2716
+ * - `from`/`to` are 1-indexed offsets derived from `skip` and the item
2717
+ * count of the current page (`from = skip + 1`,
2718
+ * `to = skip + data.length`); both stay `undefined` on an empty page.
2719
+ *
2720
+ * The `data` / `total` / `limit` key names are configurable through
2721
+ * `FeathersResponseOptions`; the `skip` key is fixed by the Feathers
2722
+ * envelope and lives as a private static.
2723
+ *
2724
+ * @see https://feathersjs.com/api/databases/common#pagination
2725
+ */
2726
+ declare class FeathersResponseStrategy implements IResponseStrategy {
2727
+ /**
2728
+ * Feathers-native name of the offset key
2729
+ *
2730
+ * Fixed by the adapter envelope; read for page derivation only.
2731
+ */
2732
+ private static readonly _skipKey;
2733
+ /**
2734
+ * Parse a Feathers pagination response into a PaginatedCollection
2735
+ *
2736
+ * @param response - The raw API response body
2737
+ * @param options - The response key name configuration
2738
+ * @returns A typed PaginatedCollection instance
2739
+ */
2740
+ paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
2741
+ }
2742
+
2743
+ /**
2744
+ * Request strategy for the JSON:API driver
2745
+ *
2746
+ * Generates URIs in the JSON:API format:
2747
+ * - Fields: `fields[articles]=title,body&fields[people]=name`
2748
+ * - Filters: `filter[status]=active`
2749
+ * - Includes: `include=author,comments.author`
2750
+ * - Pagination: `page[number]=1&page[size]=15`
2751
+ * - Sort: `sort=-created_at,name` (- prefix = DESC)
2752
+ *
2753
+ * @see https://jsonapi.org/format/
2754
+ */
2755
+ declare class JsonApiRequestStrategy extends AbstractRequestStrategy {
2756
+ /**
2757
+ * Filters, sorts, includes, per-model fields — same shape as Spatie
2758
+ * but with bracket-style pagination
2759
+ */
2760
+ readonly capabilities: IStrategyCapabilities;
2761
+ /**
2762
+ * Emit JSON:API-format query-string segments in canonical order:
2763
+ * include → fields → filters → pagination → sort
2764
+ *
2765
+ * @param state - The current query builder state
2766
+ * @param options - The query parameter key name configuration
2767
+ * @returns Ordered query-string fragments
2768
+ */
2769
+ protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
2770
+ /**
2771
+ * Append per-type field selection in bracket notation
2772
+ *
2773
+ * @param state - The current query builder state
2774
+ * @param options - The query parameter key name configuration
2775
+ * @param out - The accumulator the caller joins into the URI
2776
+ * @throws Error if the resource is missing from the fields object
2777
+ * @throws UnselectableModelError if a field type is not the resource or in includes
2778
+ */
2779
+ private _appendFields;
2780
+ /**
2781
+ * Append filter parameters in bracket notation: `filter[key]=value`
2782
+ *
2783
+ * @param state - The current query builder state
2784
+ * @param options - The query parameter key name configuration
2785
+ * @param out - The accumulator the caller joins into the URI
2786
+ */
2787
+ private _appendFilters;
2788
+ /**
2789
+ * Append include parameter as `include=author,comments.author`
2790
+ *
2791
+ * @param state - The current query builder state
2792
+ * @param options - The query parameter key name configuration
2793
+ * @param out - The accumulator the caller joins into the URI
2794
+ */
2795
+ private _appendIncludes;
2796
+ /**
2797
+ * Append JSON:API bracket pagination as `page[number]=1&page[size]=15`
2798
+ *
2799
+ * `qs.stringify` already returns the two segments joined with `&`, so we
2800
+ * push the whole string as one accumulator entry — `_join` will glue
2801
+ * it onto the rest with the same separator.
2802
+ *
2803
+ * @param state - The current query builder state
2804
+ * @param options - The query parameter key name configuration
2805
+ * @param out - The accumulator the caller joins into the URI
2806
+ */
2807
+ private _appendPagination;
2808
+ /**
2809
+ * Append sort parameter as `sort=-field1,field2` (`-` prefix = DESC)
2810
+ *
2811
+ * @param state - The current query builder state
2812
+ * @param options - The query parameter key name configuration
2813
+ * @param out - The accumulator the caller joins into the URI
2814
+ */
2815
+ private _appendSort;
2816
+ }
2817
+
2818
+ /**
2819
+ * Response strategy for the JSON:API driver
2820
+ *
2821
+ * Parses JSON:API pagination responses:
2822
+ * ```json
2823
+ * {
2824
+ * "data": [...],
2825
+ * "meta": {
2826
+ * "current-page": 1,
2827
+ * "per-page": 10,
2828
+ * "total": 100,
2829
+ * "page-count": 10,
2830
+ * "from": 1,
2831
+ * "to": 10
2832
+ * },
2833
+ * "links": {
2834
+ * "first": "url",
2835
+ * "prev": "url",
2836
+ * "next": "url",
2837
+ * "last": "url"
2838
+ * }
2839
+ * }
2840
+ * ```
2841
+ *
2842
+ * Default key paths are configured in `JsonApiResponseOptions`. The
2843
+ * traversal algorithm (dot-notation resolution + computed `from`/`to`) is
2844
+ * inherited from `AbstractDotPathResponseStrategy`; this class exists so
2845
+ * `DriverEnum.JSON_API` resolves to a distinct identity at the DI layer
2846
+ * even though the parsing logic is shared with NestJS.
2847
+ *
2848
+ * @see https://jsonapi.org/format/
2849
+ */
2850
+ declare class JsonApiResponseStrategy extends AbstractDotPathResponseStrategy {
2851
+ }
2852
+
2853
+ /**
2854
+ * Request strategy for the json-server driver
2855
+ *
2856
+ * Generates URIs in [json-server's](https://github.com/typicode/json-server)
2857
+ * query format — the de-facto standard mock REST API for prototyping:
2858
+ * - Filters: `field=value` (exact, no operator); multi-value folds to the
2859
+ * `in` list (`field:in=v1,v2`)
2860
+ * - Operator filters: colon syntax `field:op=value` — see the mapping on
2861
+ * `_formatOperatorSegments`
2862
+ * - Sorts: `_sort=-views,title` (CSV, `-` prefix = DESC)
2863
+ * - Search: `q=term` (full-text search)
2864
+ * - Pagination: `_page=N&_per_page=M`
2865
+ *
2866
+ * The underscore-prefixed system params (`_page`, `_per_page`, `_sort`)
2867
+ * and the `q` search key are fixed by the server and intentionally not
2868
+ * configurable through `QueryBuilderOptions`; they live as private
2869
+ * statics so they are visible in one place.
2870
+ *
2871
+ * json-server has no per-model field selection, no relation includes,
2872
+ * no column projection — the corresponding fluent methods throw the
2873
+ * matching `Unsupported*Error`. `ILIKE` (no case-insensitive variant),
2874
+ * `NULL` (no null check), and the PostgREST-native full-text operators
2875
+ * (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
2876
+ * `UnsupportedFilterOperatorError`.
2877
+ *
2878
+ * @see https://github.com/typicode/json-server
2879
+ */
2880
+ declare class JsonServerRequestStrategy extends AbstractRequestStrategy {
2881
+ /**
2882
+ * Filters, operator filters, sorts, global search — no per-model
2883
+ * fields, no includes, no flat select, no embedded resources
2884
+ */
2885
+ readonly capabilities: IStrategyCapabilities;
2886
+ /**
2887
+ * json-server-native names of the four hardcoded query keys
2888
+ *
2889
+ * The underscore prefix marks system params apart from filter fields;
2890
+ * these keys are fixed by the server and intentionally not
2891
+ * configurable through `QueryBuilderOptions`.
2892
+ */
2893
+ private static readonly _pageKey;
2894
+ private static readonly _perPageKey;
2895
+ private static readonly _qKey;
2896
+ private static readonly _sortKey;
2897
+ /**
2898
+ * Emit json-server-format query-string segments in canonical order:
2899
+ * filters → operator filters → _sort → q → _page → _per_page
2900
+ *
2901
+ * @param state - The current query builder state
2902
+ * @param _options - The query parameter key name configuration (unused;
2903
+ * json-server's system keys are fixed by the server)
2904
+ * @returns Ordered query-string fragments
2905
+ */
2906
+ protected parts(state: IQueryBuilderState, _options: QueryBuilderOptions): string[];
2907
+ /**
2908
+ * Append simple filter parameters
2909
+ *
2910
+ * A single value emits the bare exact-match form (`field=value`);
2911
+ * multiple values fold to the `in` list (`field:in=v1,v2`).
2912
+ *
2913
+ * @param state - The current query builder state
2914
+ * @param out - The accumulator the caller joins into the URI
2915
+ */
2916
+ private _appendFilters;
2917
+ /**
2918
+ * Append explicit operator filters in the colon syntax
2919
+ *
2920
+ * @param state - The current query builder state
2921
+ * @param out - The accumulator the caller joins into the URI
2922
+ */
2923
+ private _appendOperatorFilters;
2924
+ /**
2925
+ * Append the _page parameter
2926
+ *
2927
+ * @param state - The current query builder state
2928
+ * @param out - The accumulator the caller joins into the URI
2929
+ */
2930
+ private _appendPage;
2931
+ /**
2932
+ * Append the _per_page parameter
2933
+ *
2934
+ * @param state - The current query builder state
2935
+ * @param out - The accumulator the caller joins into the URI
2936
+ */
2937
+ private _appendPerPage;
2938
+ /**
2939
+ * Append the `q=` full-text search parameter
2940
+ *
2941
+ * @param state - The current query builder state
2942
+ * @param out - The accumulator the caller joins into the URI
2943
+ */
2944
+ private _appendSearch;
2945
+ /**
2946
+ * Append the `_sort=-views,title` CSV parameter
2947
+ *
2948
+ * @param state - The current query builder state
2949
+ * @param out - The accumulator the caller joins into the URI
2950
+ */
2951
+ private _appendSort;
2952
+ /**
2953
+ * Translate a `FilterOperatorEnum` operator filter into one or more
2954
+ * json-server `field:op=value` segments
2955
+ *
2956
+ * The mapping is library-canonical → json-server-native:
2957
+ * - `EQ` → `:eq`; `GT`/`GTE`/`LT`/`LTE` → `:gt` / `:gte` / `:lt` / `:lte`
2958
+ * - `CONTAINS` → `:contains`
2959
+ * - `SW` → `:startsWith`
2960
+ * - `IN` → `:in` (CSV)
2961
+ * - `BTW` → **two** AND-ed segments (`field:gte=min` and
2962
+ * `field:lte=max`, arity-checked)
2963
+ * - `NOT` → `:ne` — one segment per value, AND-ed
2964
+ *
2965
+ * `ILIKE` (json-server has no case-insensitive variant), `NULL` (no
2966
+ * null-check operator), and PostgREST's full-text-search operators
2967
+ * (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
2968
+ * `UnsupportedFilterOperatorError`.
2969
+ *
2970
+ * @param filter - The operator filter to translate
2971
+ * @returns One or more `field:op=value` query-string segments
2972
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
2973
+ * exactly two values
2974
+ * @throws {UnsupportedFilterOperatorError} If the operator has no
2975
+ * json-server equivalent
2976
+ */
2977
+ private _formatOperatorSegments;
2978
+ }
2979
+
2980
+ /**
2981
+ * Response strategy for the json-server driver
2982
+ *
2983
+ * Parses json-server v1 paginated responses:
2984
+ *
2985
+ * ```json
2986
+ * {
2987
+ * "first": 1,
2988
+ * "prev": null,
2989
+ * "next": 2,
2990
+ * "last": 5,
2991
+ * "pages": 5,
2992
+ * "items": 48,
2993
+ * "data": [...]
2994
+ * }
2995
+ * ```
2996
+ *
2997
+ * Uniquely among the drivers, `first` / `prev` / `next` / `last` are
2998
+ * **page numbers**, not URLs — so the navigation-URL slots on
2999
+ * `PaginatedCollection` stay `undefined` and the strategy instead uses
3000
+ * the numbers to derive position:
3001
+ *
3002
+ * - `currentPage` is `prev + 1` (`prev === null` → page **1**).
3003
+ * - `perPage` is the item count of the current page whenever `next` is
3004
+ * set (a page with a successor is necessarily full); on the last page
3005
+ * of a multi-page set it is not introspectable and stays `undefined`.
3006
+ * - `lastPage` comes straight from `pages`; `from`/`to` derive from
3007
+ * `currentPage` × `perPage` on full pages, or count back from the
3008
+ * total on the last page (`from = total - items + 1`, `to = total`).
3009
+ *
3010
+ * The `data` / `items` / `pages` key paths are configurable through
3011
+ * `JsonServerResponseOptions`; the `prev` / `next` keys are fixed by the
3012
+ * json-server envelope and live as private statics.
3013
+ *
3014
+ * @see https://github.com/typicode/json-server
3015
+ */
3016
+ declare class JsonServerResponseStrategy implements IResponseStrategy {
3017
+ /**
3018
+ * json-server-native names of the page-number navigation keys
3019
+ *
3020
+ * Fixed by the v1 envelope; read for derivation only and never
3021
+ * surfaced as URLs.
3022
+ */
3023
+ private static readonly _nextKey;
3024
+ private static readonly _prevKey;
3025
+ /**
3026
+ * Parse a json-server pagination response into a PaginatedCollection
3027
+ *
3028
+ * @param response - The raw API response body
3029
+ * @param options - The response key name configuration
3030
+ * @returns A typed PaginatedCollection instance
3031
+ */
3032
+ paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
3033
+ /**
3034
+ * Derive `from` as the 1-indexed offset of the first item on this page
3035
+ *
3036
+ * Computed from `currentPage` × `perPage` on full pages; on the last
3037
+ * page (no `next`) it counts back from the total
3038
+ * (`total - items + 1`), which also covers single-page responses.
3039
+ *
3040
+ * @param data - The items on the current page
3041
+ * @param currentPage - The current page number
3042
+ * @param next - The next page number, or null
3043
+ * @param perPage - The page size (may be undefined)
3044
+ * @param total - The total item count (may be undefined)
3045
+ * @returns The 1-indexed `from` index, or undefined when inputs insufficient
3046
+ */
3047
+ private _deriveFrom;
3048
+ /**
3049
+ * Derive `perPage` from the current page's item count
3050
+ *
3051
+ * A page with a `next` successor is necessarily full, so its item
3052
+ * count equals the page size. Without a successor the page may be
3053
+ * partial and the size is not introspectable from the body alone.
3054
+ *
3055
+ * @param next - The next page number, or null
3056
+ * @param data - The items on the current page
3057
+ * @returns The page size, or undefined
3058
+ */
3059
+ private _derivePerPage;
3060
+ /**
3061
+ * Derive `to` as the 1-indexed offset of the last item on this page
3062
+ *
3063
+ * Clamped to `total` so the last page does not report past the end;
3064
+ * on the last page (no `next`) it is simply the total.
3065
+ *
3066
+ * @param data - The items on the current page
3067
+ * @param currentPage - The current page number
3068
+ * @param next - The next page number, or null
3069
+ * @param perPage - The page size (may be undefined)
3070
+ * @param total - The total item count (may be undefined)
3071
+ * @returns The 1-indexed `to` index, or undefined when inputs insufficient
3072
+ */
3073
+ private _deriveTo;
3074
+ }
3075
+
3076
+ /**
3077
+ * Request strategy for the Laravel (pagination-only) driver
3078
+ *
3079
+ * Generates simple pagination URIs:
3080
+ * - `/{resource}?limit=N&page=N`
3081
+ *
3082
+ * Filters, sorts, fields, includes, search, and select in state are ignored.
3083
+ */
3084
+ declare class LaravelRequestStrategy extends AbstractRequestStrategy {
3085
+ /**
3086
+ * Pagination-only driver — no filtering, sorting, or column selection
3087
+ */
3088
+ readonly capabilities: IStrategyCapabilities;
3089
+ /**
3090
+ * Emit only the pagination params; filters/sorts/etc. are ignored
3091
+ *
3092
+ * @param state - The current query builder state
3093
+ * @param options - The query parameter key name configuration
3094
+ * @returns The two pagination query-string fragments
3095
+ */
3096
+ protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
3097
+ }
3098
+
3099
+ /**
3100
+ * Base class for response strategies whose pagination metadata is a flat
3101
+ * key-value envelope on the response body
3102
+ *
3103
+ * Laravel's stock pagination and Spatie's `QueryBuilder` both emit the
3104
+ * same flat shape — `{ data, current_page, total, per_page, from, to,
3105
+ * next_page_url, prev_page_url, first_page_url, last_page, last_page_url
3106
+ * }` — and both response strategies were duplicating the byte-identical
3107
+ * `new PaginatedCollection(response[options.X], ...)` body before this
3108
+ * base existed. Concrete classes now extend and provide only the
3109
+ * docstring describing their driver's specific shape (see
3110
+ * `LaravelResponseStrategy`, `SpatieResponseStrategy`).
3111
+ *
3112
+ * Drivers whose pagination metadata is a nested envelope (JSON:API,
3113
+ * NestJS, Strapi) extend `AbstractDotPathResponseStrategy` instead.
3114
+ * Drivers whose metadata comes from HTTP headers (PostgREST) or is
3115
+ * derived from response URLs (DRF) implement `IResponseStrategy`
3116
+ * directly.
3117
+ */
3118
+ declare abstract class AbstractFlatResponseStrategy implements IResponseStrategy {
3119
+ /**
3120
+ * Parse a flat-envelope pagination response into a PaginatedCollection
3121
+ *
3122
+ * @param response - The raw API response object
3123
+ * @param options - The response key name configuration
3124
+ * @returns A typed PaginatedCollection instance
3125
+ */
3126
+ paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
3127
+ }
3128
+
3129
+ /**
3130
+ * Response strategy for the Laravel (pagination-only) driver
3131
+ *
3132
+ * Parses flat Laravel pagination responses:
3133
+ * ```json
3134
+ * {
3135
+ * "data": [...],
3136
+ * "current_page": 1,
3137
+ * "total": 100,
3138
+ * "per_page": 15,
3139
+ * "from": 1,
3140
+ * "to": 15,
3141
+ * "next_page_url": "...",
3142
+ * "prev_page_url": "...",
3143
+ * "first_page_url": "...",
3144
+ * "last_page": 7,
3145
+ * "last_page_url": "..."
3146
+ * }
3147
+ * ```
3148
+ *
3149
+ * The traversal algorithm (flat `response[options.X]` lookups) is
3150
+ * inherited from `AbstractFlatResponseStrategy`; this class exists so
3151
+ * `DriverEnum.LARAVEL` resolves to a distinct identity at the DI layer
3152
+ * even though the parsing logic is shared with Spatie.
3153
+ */
3154
+ declare class LaravelResponseStrategy extends AbstractFlatResponseStrategy {
3155
+ }
3156
+
3157
+ /**
3158
+ * Request strategy for the NestJS (nestjs-paginate) driver
3159
+ *
3160
+ * Generates URIs in the NestJS paginate format:
3161
+ * - Simple filters: `filter.field=value`
3162
+ * - Operator filters: `filter.field=$operator:value`
3163
+ * - Sorts: `sortBy=field1:DESC,field2:ASC`
3164
+ * - Select: `select=col1,col2`
3165
+ * - Search: `search=term`
3166
+ * - Pagination: `limit=N&page=N`
3167
+ *
3168
+ * @see https://github.com/ppetzold/nestjs-paginate
3169
+ */
3170
+ declare class NestjsRequestStrategy extends AbstractRequestStrategy {
3171
+ /**
3172
+ * Filters, operator filters, sorts, flat select, global search — no
3173
+ * per-model fields, no includes
3174
+ */
3175
+ readonly capabilities: IStrategyCapabilities;
3176
+ /**
3177
+ * Validate that the given limit is accepted by nestjs-paginate
3178
+ *
3179
+ * Accepts any integer `>= 1` as a page size, plus `-1` which nestjs-paginate
3180
+ * interprets as "fetch all items" (server must opt-in via `maxLimit: -1`).
3181
+ *
3182
+ * @param limit - The limit value to validate
3183
+ * @throws {InvalidLimitError} If the value is not an integer, or is 0, or is a negative number other than -1
3184
+ */
3185
+ validateLimit(limit: number): void;
3186
+ /**
3187
+ * Emit NestJS-format query-string segments in canonical order:
3188
+ * filters → operator filters → sortBy → select → search → limit → page
3189
+ *
3190
+ * @param state - The current query builder state
3191
+ * @param options - The query parameter key name configuration
3192
+ * @returns Ordered query-string fragments
3193
+ */
3194
+ protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
3195
+ /**
3196
+ * Append simple filter parameters as `filter.field=value1,value2`
3197
+ *
3198
+ * @param state - The current query builder state
3199
+ * @param options - The query parameter key name configuration
3200
+ * @param out - The accumulator the caller joins into the URI
3201
+ */
3202
+ private _appendFilters;
3203
+ /**
3204
+ * Append the limit parameter
3205
+ *
3206
+ * @param state - The current query builder state
3207
+ * @param options - The query parameter key name configuration
3208
+ * @param out - The accumulator the caller joins into the URI
3209
+ */
3210
+ private _appendLimit;
3211
+ /**
3212
+ * Append operator-filter parameters as `filter.field=$op:value`
3213
+ *
3214
+ * Groups by field; multi-value operators ($in, $btw) join values with commas.
3215
+ *
3216
+ * @param state - The current query builder state
3217
+ * @param options - The query parameter key name configuration
3218
+ * @param out - The accumulator the caller joins into the URI
3219
+ */
3220
+ private _appendOperatorFilters;
3221
+ /**
3222
+ * Append the page parameter
3223
+ *
3224
+ * @param state - The current query builder state
3225
+ * @param options - The query parameter key name configuration
3226
+ * @param out - The accumulator the caller joins into the URI
3227
+ */
3228
+ private _appendPage;
3229
+ /**
3230
+ * Append the search parameter as `search=term`
3231
+ *
3232
+ * @param state - The current query builder state
3233
+ * @param options - The query parameter key name configuration
3234
+ * @param out - The accumulator the caller joins into the URI
3235
+ */
3236
+ private _appendSearch;
3237
+ /**
3238
+ * Append the select parameter as `select=col1,col2`
3239
+ *
3240
+ * @param state - The current query builder state
3241
+ * @param options - The query parameter key name configuration
3242
+ * @param out - The accumulator the caller joins into the URI
3243
+ */
3244
+ private _appendSelect;
3245
+ /**
3246
+ * Append sort parameter as `sortBy=field1:DESC,field2:ASC`
3247
+ *
3248
+ * @param state - The current query builder state
3249
+ * @param options - The query parameter key name configuration
3250
+ * @param out - The accumulator the caller joins into the URI
3251
+ */
3252
+ private _appendSort;
3253
+ }
3254
+
3255
+ /**
3256
+ * Response strategy for the NestJS (nestjs-paginate) driver
3257
+ *
3258
+ * Parses nested NestJS pagination responses:
3259
+ * ```json
3260
+ * {
3261
+ * "data": [...],
3262
+ * "meta": {
3263
+ * "currentPage": 1,
3264
+ * "totalItems": 100,
3265
+ * "itemsPerPage": 10,
3266
+ * "totalPages": 10
3267
+ * },
3268
+ * "links": {
3269
+ * "first": "url",
3270
+ * "previous": "url",
3271
+ * "next": "url",
3272
+ * "last": "url",
3273
+ * "current": "url"
3274
+ * }
3275
+ * }
3276
+ * ```
3277
+ *
3278
+ * Default key paths are configured in `NestjsResponseOptions`. The
3279
+ * traversal algorithm (dot-notation resolution + computed `from`/`to`) is
3280
+ * inherited from `AbstractDotPathResponseStrategy`; this class exists so
3281
+ * `DriverEnum.NESTJS` resolves to a distinct identity at the DI layer
3282
+ * even though the parsing logic is shared with JSON:API.
3283
+ *
3284
+ * @see https://github.com/ppetzold/nestjs-paginate
3285
+ */
3286
+ declare class NestjsResponseStrategy extends AbstractDotPathResponseStrategy {
3287
+ }
3288
+
3289
+ /**
3290
+ * Request strategy for the @nestjsx/crud driver
3291
+ *
3292
+ * Generates URIs in [@nestjsx/crud's pipe-delimited query format](https://github.com/nestjsx/crud/wiki/Requests):
3293
+ * - Filters: `filter=field||$eq||value` (repeatable; multi-value
3294
+ * collapses to `filter=field||$in||v1,v2`)
3295
+ * - Operator filters: `filter=field||$op||value` (translated from
3296
+ * `FilterOperatorEnum` — `CONTAINS`→`$cont`, `ILIKE`→`$contL`,
3297
+ * `SW`→`$starts`, `BTW`→`$between`, `NOT`→`$ne`/`$notin`,
3298
+ * `NULL`→`$isnull`/`$notnull` with no value segment)
3299
+ * - Joins: `join=relation` (repeatable, from `addIncludes`)
3300
+ * - Field selection (flat): `fields=col1,col2` (from `addSelect`)
3301
+ * - Sorts: `sort=field,ASC` (repeatable, uppercase direction)
3302
+ * - Pagination (page-based): `page=N&limit=N`
3303
+ *
3304
+ * The JSON-shaped `s={...}` search parameter is intentionally out of
3305
+ * scope: it is not a plain search term, so `setSearch` throws
3306
+ * `UnsupportedSearchError` on this driver. PostgREST-native full-text
3307
+ * search operators (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
3308
+ * `UnsupportedFilterOperatorError`.
3309
+ *
3310
+ * @see https://github.com/nestjsx/crud/wiki/Requests
3311
+ */
3312
+ declare class NestjsxCrudRequestStrategy extends AbstractRequestStrategy {
3313
+ /**
3314
+ * Filters, operator filters, joins (`includes`), flat field selection
3315
+ * (`select`), sorts — no per-model fields, no global search (the `s`
3316
+ * parameter is JSON-shaped, not a plain term)
3317
+ */
3318
+ readonly capabilities: IStrategyCapabilities;
3319
+ /**
3320
+ * @nestjsx/crud-native names of the four hardcoded query keys
3321
+ *
3322
+ * The wire format is fixed (the server's `CrudRequestInterceptor`
3323
+ * reads `fields`, `filter`, `join`, and `sort`); these keys are
3324
+ * intentionally not configurable through `QueryBuilderOptions` and
3325
+ * live as private statics so they are visible in one place.
3326
+ */
3327
+ private static readonly _fieldsKey;
3328
+ private static readonly _filterKey;
3329
+ private static readonly _joinKey;
3330
+ private static readonly _sortKey;
3331
+ /**
3332
+ * Pipe delimiter separating field, operator, and value segments
3333
+ */
3334
+ private static readonly _separator;
3335
+ /**
3336
+ * Emit @nestjsx/crud-format query-string segments in canonical order:
3337
+ * fields → filters → operator filters → join → sort → limit → page
3338
+ *
3339
+ * @param state - The current query builder state
3340
+ * @param options - The query parameter key name configuration (used
3341
+ * for `page` / `limit`, whose defaults match the wire format; the
3342
+ * `fields` / `filter` / `join` / `sort` keys are fixed by the server)
3343
+ * @returns Ordered query-string fragments
3344
+ */
3345
+ protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
3346
+ /**
3347
+ * Append `fields=col1,col2` from the flat select array
3348
+ *
3349
+ * @param state - The current query builder state
3350
+ * @param out - The accumulator the caller joins into the URI
3351
+ */
3352
+ private _appendFields;
3353
+ /**
3354
+ * Append simple filters as repeatable `filter=field||$eq||value` params
3355
+ *
3356
+ * Single-value filters fold to `$eq`; multi-value filters fold to
3357
+ * `$in` with comma-joined values.
3358
+ *
3359
+ * @param state - The current query builder state
3360
+ * @param out - The accumulator the caller joins into the URI
3361
+ */
3362
+ private _appendFilters;
3363
+ /**
3364
+ * Append `join=relation` params from the includes array
3365
+ *
3366
+ * Per-relation field projection (`join=relation||f1,f2`) is not
3367
+ * expressible through the current state shape and is out of scope.
3368
+ *
3369
+ * @param state - The current query builder state
3370
+ * @param out - The accumulator the caller joins into the URI
3371
+ */
3372
+ private _appendJoin;
3373
+ /**
3374
+ * Append the limit parameter
3375
+ *
3376
+ * @param state - The current query builder state
3377
+ * @param options - The query parameter key name configuration
3378
+ * @param out - The accumulator the caller joins into the URI
3379
+ */
3380
+ private _appendLimit;
3381
+ /**
3382
+ * Append operator filters as repeatable `filter=field||$op||value` params
3383
+ *
3384
+ * @param state - The current query builder state
3385
+ * @param out - The accumulator the caller joins into the URI
3386
+ */
3387
+ private _appendOperatorFilters;
3388
+ /**
3389
+ * Append the page parameter
3390
+ *
3391
+ * @param state - The current query builder state
3392
+ * @param options - The query parameter key name configuration
3393
+ * @param out - The accumulator the caller joins into the URI
3394
+ */
3395
+ private _appendPage;
3396
+ /**
3397
+ * Append `sort=field,ASC` params, one per sort rule
3398
+ *
3399
+ * @param state - The current query builder state
3400
+ * @param out - The accumulator the caller joins into the URI
3401
+ */
3402
+ private _appendSort;
3403
+ /**
3404
+ * Translate a `FilterOperatorEnum` operator filter into @nestjsx/crud's
3405
+ * `$operator||value` condition segment
3406
+ *
3407
+ * The mapping is library-canonical → @nestjsx/crud-native:
3408
+ * - `EQ`/`GT`/`GTE`/`LT`/`LTE`/`IN` → identity (same operator name)
3409
+ * - `CONTAINS` → `$cont`; `ILIKE` → `$contL` (case-insensitive contains)
3410
+ * - `SW` → `$starts`
3411
+ * - `BTW` → `$between` with `min,max` (arity-checked)
3412
+ * - `NOT` → `$ne` (single value) / `$notin` (multi-value)
3413
+ * - `NULL` → `$isnull` (when value is `true`) / `$notnull` (when value
3414
+ * is `false`); both emit **no value segment**; arity- and type-checked
3415
+ *
3416
+ * PostgREST's full-text-search operators (`FTS`, `PHFTS`, `PLFTS`,
3417
+ * `WFTS`) have no @nestjsx/crud equivalent and throw
3418
+ * `UnsupportedFilterOperatorError`.
3419
+ *
3420
+ * @param filter - The operator filter to translate
3421
+ * @returns The `$operator||value` (or bare `$operator`) condition segment
3422
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
3423
+ * exactly two values, or `NULL` does not receive exactly one boolean
3424
+ * @throws {UnsupportedFilterOperatorError} If the operator is a
3425
+ * PostgREST-only FTS variant
3426
+ */
3427
+ private _formatOperatorCondition;
3428
+ }
3429
+
3430
+ /**
3431
+ * Response strategy for the @nestjsx/crud driver
3432
+ *
3433
+ * Parses @nestjsx/crud's `getMany` envelope:
3434
+ * ```json
3435
+ * {
3436
+ * "data": [{ "id": 1, "name": "John" }],
3437
+ * "count": 10,
3438
+ * "total": 48,
3439
+ * "page": 2,
3440
+ * "pageCount": 5
3441
+ * }
3442
+ * ```
3443
+ *
3444
+ * Default key paths are configured in `NestjsxCrudResponseOptions`. The
3445
+ * envelope carries no `from`/`to` indices and no navigation links, so
3446
+ * `from`/`to` are computed from `page` × `count` by the inherited
3447
+ * traversal algorithm and the URL slots resolve to `undefined` unless
3448
+ * the consumer overrides their paths via `IPaginationConfig`.
3449
+ *
3450
+ * Note that `count` is the number of entities **on the current page**,
3451
+ * not the requested page size — on the last page of a result set the
3452
+ * derived `from`/`to` can underestimate. Consumers needing exact
3453
+ * indices should compute them from the requested limit instead.
3454
+ *
3455
+ * The dot-notation traversal is inherited from
3456
+ * `AbstractDotPathResponseStrategy`; this class exists so
3457
+ * `DriverEnum.NESTJSX_CRUD` resolves to a distinct identity at the DI
3458
+ * layer even though the parsing logic is shared with JSON:API, NestJS,
3459
+ * and Strapi.
3460
+ *
3461
+ * @see https://github.com/nestjsx/crud/wiki/Requests
3462
+ */
3463
+ declare class NestjsxCrudResponseStrategy extends AbstractDotPathResponseStrategy {
3464
+ }
3465
+
3466
+ /**
3467
+ * Request strategy for the OData v4 driver
3468
+ *
3469
+ * Generates URIs using [OData's system query options](https://www.odata.org/getting-started/basic-tutorial/#queryData):
3470
+ * - Filters: a single `$filter=` parameter holding ` and `-joined terms in
3471
+ * OData's expression language (`Price gt 20 and Category eq 'Electronics'`)
3472
+ * - Operator filters: translated from `FilterOperatorEnum` — see the
3473
+ * mapping on `_formatOperatorTerms`
3474
+ * - Sorts: `$orderby=field asc,other desc` (CSV with explicit direction)
3475
+ * - Select: `$select=col1,col2`
3476
+ * - Expand: `$expand=rel,other($select=col1,col2)` — plain relations come
3477
+ * from `addIncludes`, column-projected ones from `addEmbedded`
3478
+ * - Search: `$search=term` (OData v4 free-text search)
3479
+ * - Pagination: `$top=N&$skip=M` (skip derived from state.page) plus a
3480
+ * constant `$count=true` so responses carry the `@odata.count` total
3481
+ * the response strategy needs
3482
+ *
3483
+ * The `$`-prefixed parameter names are fixed by the OData specification
3484
+ * and intentionally not configurable through `QueryBuilderOptions`; they
3485
+ * live as private statics so they are visible in one place. String
3486
+ * literals are single-quoted with embedded quotes doubled (`'O''Brien'`)
3487
+ * per the OData ABNF; numbers and booleans are emitted bare.
3488
+ *
3489
+ * PostgREST-native full-text search operators (`FTS`, `PHFTS`, `PLFTS`,
3490
+ * `WFTS`) throw `UnsupportedFilterOperatorError` — use `$search` or the
3491
+ * `CONTAINS` / `ILIKE` operator filters instead.
3492
+ *
3493
+ * @see https://www.odata.org/
3494
+ * @see https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html
3495
+ */
3496
+ declare class OdataRequestStrategy extends AbstractRequestStrategy {
3497
+ /**
3498
+ * Filters, operator filters, sorts, flat select, includes and embedded
3499
+ * (both folding into `$expand`), global search — no per-model fields
3500
+ * (OData has no JSON:API-style `fields[type]` projection)
3501
+ */
3502
+ readonly capabilities: IStrategyCapabilities;
3503
+ /**
3504
+ * OData-native names of the system query options
3505
+ *
3506
+ * The `$` prefix is mandated by the OData URL conventions; these keys
3507
+ * are intentionally not configurable through `QueryBuilderOptions` and
3508
+ * live as private statics so they are visible in one place.
3509
+ */
3510
+ private static readonly _countKey;
3511
+ private static readonly _expandKey;
3512
+ private static readonly _filterKey;
3513
+ private static readonly _orderbyKey;
3514
+ private static readonly _searchKey;
3515
+ private static readonly _selectKey;
3516
+ private static readonly _skipKey;
3517
+ private static readonly _topKey;
3518
+ /**
3519
+ * Emit OData-format query-string segments in canonical order:
3520
+ * $filter → $orderby → $select → $expand → $search → $count → $top → $skip
3521
+ *
3522
+ * @param state - The current query builder state
3523
+ * @param _options - The query parameter key name configuration (unused —
3524
+ * every OData system query option name is fixed by the specification)
3525
+ * @returns Ordered query-string fragments
3526
+ */
3527
+ protected parts(state: IQueryBuilderState, _options: QueryBuilderOptions): string[];
3528
+ /**
3529
+ * Append the constant `$count=true` parameter
3530
+ *
3531
+ * Always emitted: the OData response strategy reads the total from
3532
+ * `@odata.count`, which servers only include when the request asks
3533
+ * for it.
3534
+ *
3535
+ * @param out - The accumulator the caller joins into the URI
3536
+ */
3537
+ private _appendCount;
3538
+ /**
3539
+ * Append the `$expand=` parameter combining includes and embedded
3540
+ * relations
3541
+ *
3542
+ * Plain relations from `addIncludes` emit bare (`rel`); embedded
3543
+ * relations from `addEmbedded` emit with an inline projection
3544
+ * (`rel($select=col1,col2)`) or bare when no columns were given. A
3545
+ * relation present in both folds into the embedded fragment, which
3546
+ * carries the column information.
3547
+ *
3548
+ * @param state - The current query builder state
3549
+ * @param out - The accumulator the caller joins into the URI
3550
+ */
3551
+ private _appendExpand;
3552
+ /**
3553
+ * Append the single `$filter=` parameter combining simple and operator
3554
+ * filters
3555
+ *
3556
+ * Each term is one OData boolean expression; terms join with ` and `.
3557
+ * Simple single-value filters fold to `eq`; simple multi-value filters
3558
+ * fold to the `in` list operator (`field in ('v1','v2')`).
3559
+ *
3560
+ * @param state - The current query builder state
3561
+ * @param out - The accumulator the caller joins into the URI
3562
+ */
3563
+ private _appendFilter;
3564
+ /**
3565
+ * Append the `$orderby=field asc,other desc` CSV parameter
3566
+ *
3567
+ * @param state - The current query builder state
3568
+ * @param out - The accumulator the caller joins into the URI
3569
+ */
3570
+ private _appendOrderby;
3571
+ /**
3572
+ * Append the `$search=` free-text search parameter
3573
+ *
3574
+ * @param state - The current query builder state
3575
+ * @param out - The accumulator the caller joins into the URI
3576
+ */
3577
+ private _appendSearch;
3578
+ /**
3579
+ * Append the `$select=col1,col2` projection parameter
3580
+ *
3581
+ * @param state - The current query builder state
3582
+ * @param out - The accumulator the caller joins into the URI
3583
+ */
3584
+ private _appendSelect;
3585
+ /**
3586
+ * Append the `$skip=` parameter, derived from state.page
3587
+ *
3588
+ * OData uses offset-based pagination: the skip is computed as
3589
+ * `(page - 1) * limit`. Omitted when the skip would be 0 (i.e. page 1)
3590
+ * since OData defaults to no skip and dropping it keeps the URI shorter.
3591
+ *
3592
+ * @param state - The current query builder state
3593
+ * @param out - The accumulator the caller joins into the URI
3594
+ */
3595
+ private _appendSkip;
3596
+ /**
3597
+ * Append the `$top=` page-size parameter
3598
+ *
3599
+ * @param state - The current query builder state
3600
+ * @param out - The accumulator the caller joins into the URI
3601
+ */
3602
+ private _appendTop;
3603
+ /**
3604
+ * Format a filter value as an OData primitive literal
3605
+ *
3606
+ * Strings are single-quoted with embedded single quotes doubled
3607
+ * (`'O''Brien'`) per the OData ABNF; numbers and booleans are emitted
3608
+ * bare.
3609
+ *
3610
+ * @param value - The raw filter value
3611
+ * @returns The OData-formatted literal
3612
+ */
3613
+ private _formatLiteral;
3614
+ /**
3615
+ * Translate a `FilterOperatorEnum` operator filter into one or more
3616
+ * OData boolean expressions
3617
+ *
3618
+ * The mapping is library-canonical → OData-native:
3619
+ * - `EQ` → `eq`; `GT`/`GTE`/`LT`/`LTE` → `gt` / `ge` / `lt` / `le`
3620
+ * - `CONTAINS` → `contains(field,'val')`
3621
+ * - `ILIKE` → `contains(tolower(field),tolower('val'))` (case-insensitive
3622
+ * contains)
3623
+ * - `SW` → `startswith(field,'val')`
3624
+ * - `IN` → `field in ('v1','v2')` (OData v4.01 list operator)
3625
+ * - `BTW` → **two** AND-ed terms (`field ge min` and `field le max`,
3626
+ * arity-checked)
3627
+ * - `NOT` → `ne` — one term per value, AND-ed (`field ne v1 and field ne v2`)
3628
+ * - `NULL` → `field eq null` (when value is `true`) / `field ne null`
3629
+ * (when value is `false`); arity- and type-checked
3630
+ *
3631
+ * PostgREST's full-text-search operators (`FTS`, `PHFTS`, `PLFTS`,
3632
+ * `WFTS`) have no OData equivalent and throw
3633
+ * `UnsupportedFilterOperatorError`.
3634
+ *
3635
+ * @param filter - The operator filter to translate
3636
+ * @returns One or more OData boolean expressions ready to ` and `-join
3637
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
3638
+ * exactly two values, or `NULL` does not receive exactly one boolean
3639
+ * @throws {UnsupportedFilterOperatorError} If the operator is a
3640
+ * PostgREST-only FTS variant
3641
+ */
3642
+ private _formatOperatorTerms;
3643
+ }
3644
+
3645
+ /**
3646
+ * Response strategy for the OData v4 driver
3647
+ *
3648
+ * Parses OData collection responses:
3649
+ *
3650
+ * ```json
3651
+ * {
3652
+ * "@odata.context": "https://api.example.com/$metadata#Products",
3653
+ * "@odata.count": 100,
3654
+ * "@odata.nextLink": "https://api.example.com/Products?$count=true&$top=10&$skip=30",
3655
+ * "value": [...]
3656
+ * }
3657
+ * ```
3658
+ *
3659
+ * OData emits no current-page or page-size field in the body, so this
3660
+ * strategy **derives** them by inspecting the `@odata.nextLink` URL:
3661
+ *
3662
+ * - `perPage` comes from the link's `$top` param, falling back to the
3663
+ * item count of the current (necessarily full) page when the link
3664
+ * carries no `$top`.
3665
+ * - `currentPage` is `$skip ÷ perPage` — the next page starts where the
3666
+ * current one ends. Without a usable link (`$skiptoken`-based
3667
+ * server-driven paging, or the last page) the strategy falls back to
3668
+ * page **1**, which is only guaranteed correct for single-page results.
3669
+ * - `lastPage` is `ceil(total ÷ perPage)`; on a link-less response it
3670
+ * resolves to 1 when the page provably holds the whole result set.
3671
+ *
3672
+ * The total requires `$count=true` on the request — the request strategy
3673
+ * always emits it. Envelope keys contain **literal dots** (`@odata.count`),
3674
+ * so key paths from `OdataResponseOptions` are read with flat bracket
3675
+ * access, never dot-path traversal.
3676
+ *
3677
+ * @see https://docs.oasis-open.org/odata/odata-json-format/v4.01/odata-json-format-v4.01.html
3678
+ */
3679
+ declare class OdataResponseStrategy implements IResponseStrategy {
3680
+ /**
3681
+ * Parse an OData collection response into a PaginatedCollection
3682
+ *
3683
+ * @param response - The raw API response body
3684
+ * @param options - The response key name configuration
3685
+ * @returns A typed PaginatedCollection instance
3686
+ */
3687
+ paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
3688
+ /**
3689
+ * Derive the current page number from the `@odata.nextLink` URL
3690
+ *
3691
+ * The next page starts where the current one ends, so
3692
+ * `currentPage = $skip ÷ perPage` (e.g. `$skip=30` with `$top=10` →
3693
+ * page 3). Falls back to **1** when the link is absent (last or only
3694
+ * page), carries no `$skip` (`$skiptoken`-based paging), or the page
3695
+ * size is unknown.
3696
+ *
3697
+ * @param nextPageUrl - The `@odata.nextLink` from the response, or null
3698
+ * @param perPage - The derived page size (may be undefined)
3699
+ * @returns The current page number
3700
+ */
3701
+ private _deriveCurrentPage;
3702
+ /**
3703
+ * Derive `from` as the 1-indexed offset of the first item on this page
3704
+ *
3705
+ * Computed from `currentPage` × `perPage` when the page size is known;
3706
+ * on a link-less single page it is 1 whenever items are present.
3707
+ *
3708
+ * @param nextPageUrl - The `@odata.nextLink` from the response, or null
3709
+ * @param data - The items on the current page
3710
+ * @param currentPage - The current page number
3711
+ * @param perPage - The page size (may be undefined)
3712
+ * @returns The 1-indexed `from` index, or undefined when inputs insufficient
3713
+ */
3714
+ private _deriveFrom;
3715
+ /**
3716
+ * Derive the last page number
3717
+ *
3718
+ * `ceil(total ÷ perPage)` when both are known; a link-less response
3719
+ * that provably holds the entire non-empty result set resolves to 1.
3720
+ *
3721
+ * @param nextPageUrl - The `@odata.nextLink` from the response, or null
3722
+ * @param data - The items on the current page
3723
+ * @param total - The total item count
3724
+ * @param perPage - The page size
3725
+ * @returns The last page number, or undefined when inputs insufficient
3726
+ */
3727
+ private _deriveLastPage;
3728
+ /**
3729
+ * Derive `perPage` from the `@odata.nextLink` URL
3730
+ *
3731
+ * Reads the link's `$top` param. When the link exists but carries no
3732
+ * `$top` (server-driven page size), the current page is necessarily
3733
+ * full, so its item count equals the page size. Without a link the
3734
+ * page may be partial and the size is not introspectable.
3735
+ *
3736
+ * @param nextPageUrl - The `@odata.nextLink` from the response, or null
3737
+ * @param data - The items on the current page
3738
+ * @returns The page size, or undefined
3739
+ */
3740
+ private _derivePerPage;
3741
+ /**
3742
+ * Derive `to` as the 1-indexed offset of the last item on this page
3743
+ *
3744
+ * Clamped to `total` so the last page does not report past the end;
3745
+ * on a link-less single page it is the item count.
3746
+ *
3747
+ * @param nextPageUrl - The `@odata.nextLink` from the response, or null
3748
+ * @param data - The items on the current page
3749
+ * @param currentPage - The current page number
3750
+ * @param perPage - The page size (may be undefined)
3751
+ * @param total - The total item count (may be undefined)
3752
+ * @returns The 1-indexed `to` index, or undefined when inputs insufficient
3753
+ */
3754
+ private _deriveTo;
3755
+ /**
3756
+ * Extract an integer query parameter from an OData pagination URL
3757
+ *
3758
+ * @param url - The URL to parse
3759
+ * @param name - The query-parameter name to look up (e.g. `$skip`)
3760
+ * @returns The integer value, or undefined
3761
+ */
3762
+ private _extractNumberParam;
3763
+ /**
3764
+ * Extract a single query parameter from a URL via the WHATWG URL parser
3765
+ *
3766
+ * OData permits **relative** `@odata.nextLink` values, so parsing
3767
+ * retries against a placeholder base before giving up. Returns
3768
+ * undefined when the URL is unparseable or the parameter is absent.
3769
+ *
3770
+ * @param url - The URL to parse
3771
+ * @param name - The query-parameter name to look up
3772
+ * @returns The raw string value of the parameter, or undefined
3773
+ */
3774
+ private _extractQueryParam;
3775
+ }
3776
+
3777
+ /**
3778
+ * Request strategy for the Payload CMS driver
3779
+ *
3780
+ * Generates URIs in [Payload's REST query format](https://payloadcms.com/docs/queries/overview):
3781
+ * - Filters: `where[field][equals]=value` (multi-value collapses to
3782
+ * `where[field][in]=v1,v2` CSV)
3783
+ * - Operator filters: `where[field][op]=value` (translated from
3784
+ * `FilterOperatorEnum` — `BTW`→`greater_than_equal`+`less_than_equal`
3785
+ * pair, `NOT`→`not_equals`/`not_in`, `NULL`→`exists` with inverted
3786
+ * boolean)
3787
+ * - Sorts: `sort=-createdAt,title` (CSV, `-` prefix = DESC)
3788
+ * - Field selection (flat): `select[col1]=true&select[col2]=true`
3789
+ * - Pagination (page-based): `page=N&limit=M`
3790
+ *
3791
+ * The `where` / `sort` / `select` / `page` / `limit` keys are fixed by
3792
+ * Payload's REST endpoints and intentionally not configurable through
3793
+ * `QueryBuilderOptions`; they live as private statics so they are
3794
+ * visible in one place.
3795
+ *
3796
+ * Relationship population is controlled by Payload's numeric `depth`
3797
+ * param, not a named-relation list — `addIncludes` therefore throws
3798
+ * `UnsupportedIncludesError` (pass `depth` through your HTTP layer if
3799
+ * needed). There is no per-model field selection and no global search
3800
+ * param. `SW` (no starts-with operator) and the PostgREST-native
3801
+ * full-text operators (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
3802
+ * `UnsupportedFilterOperatorError`.
3803
+ *
3804
+ * @see https://payloadcms.com/docs/queries/overview
3805
+ */
3806
+ declare class PayloadRequestStrategy extends AbstractRequestStrategy {
3807
+ /**
3808
+ * Filters, operator filters, sorts, flat field selection (`select`)
3809
+ * — no per-model fields, no includes (numeric `depth` instead), no
3810
+ * global search, no embedded resources
3811
+ */
3812
+ readonly capabilities: IStrategyCapabilities;
3813
+ /**
3814
+ * Payload-native names of the five hardcoded query keys
3815
+ *
3816
+ * Fixed by the REST endpoints and intentionally not configurable
3817
+ * through `QueryBuilderOptions`.
3818
+ */
3819
+ private static readonly _limitKey;
3820
+ private static readonly _pageKey;
3821
+ private static readonly _selectKey;
3822
+ private static readonly _sortKey;
3823
+ private static readonly _whereKey;
3824
+ /**
3825
+ * Emit Payload-format query-string segments in canonical order:
3826
+ * where (merged) → sort → select → page → limit
3827
+ *
3828
+ * Simple filters and operator filters share a single `where` wrapper
3829
+ * so qs emits one ordered bracket structure rather than two duplicate
3830
+ * top-level `where[...]` blocks.
3831
+ *
3832
+ * @param state - The current query builder state
3833
+ * @param _options - The query parameter key name configuration (unused;
3834
+ * Payload's wire keys are fixed by the server)
3835
+ * @returns Ordered query-string fragments
3836
+ */
3837
+ protected parts(state: IQueryBuilderState, _options: QueryBuilderOptions): string[];
3838
+ /**
3839
+ * Append the `page=` / `limit=` pagination pair
3840
+ *
3841
+ * @param state - The current query builder state
3842
+ * @param out - The accumulator the caller joins into the URI
3843
+ */
3844
+ private _appendPagination;
3845
+ /**
3846
+ * Append `select[col]=true` flags from the flat select array
3847
+ *
3848
+ * Payload's select API is an object of `true` flags rather than a
3849
+ * CSV; nested selection (`select[group.field]=true`) passes through
3850
+ * when given as a dotted column name.
3851
+ *
3852
+ * @param state - The current query builder state
3853
+ * @param out - The accumulator the caller joins into the URI
3854
+ */
3855
+ private _appendSelect;
3856
+ /**
3857
+ * Append the `sort=-createdAt,title` CSV parameter
3858
+ *
3859
+ * @param state - The current query builder state
3860
+ * @param out - The accumulator the caller joins into the URI
3861
+ */
3862
+ private _appendSort;
3863
+ /**
3864
+ * Append the unified `where[...]` wrapper combining simple filters
3865
+ * and operator filters
3866
+ *
3867
+ * Both kinds emit into the same nested object under `where` so qs
3868
+ * produces a single bracketed block per request. Simple single-value
3869
+ * filters fold to `equals`; simple multi-value filters fold to the
3870
+ * `in` CSV. Operator filters then merge into the same per-field map,
3871
+ * potentially co-existing with a simple filter on the same field.
3872
+ *
3873
+ * @param state - The current query builder state
3874
+ * @param out - The accumulator the caller joins into the URI
3875
+ */
3876
+ private _appendWhere;
3877
+ /**
3878
+ * Translate a `FilterOperatorEnum` operator filter into Payload's
3879
+ * `operator → value` payload shape
3880
+ *
3881
+ * The mapping is library-canonical → Payload-native:
3882
+ * - `EQ` → `equals`
3883
+ * - `GT`/`GTE`/`LT`/`LTE` → `greater_than` / `greater_than_equal` /
3884
+ * `less_than` / `less_than_equal`
3885
+ * - `CONTAINS` → `contains` (case-insensitive substring)
3886
+ * - `ILIKE` → `like` (case-insensitive, word-based)
3887
+ * - `IN` → `in` (CSV)
3888
+ * - `BTW` → `greater_than_equal` + `less_than_equal` pair in one
3889
+ * payload (arity-checked)
3890
+ * - `NOT` → `not_equals` (single value) / `not_in` (multi-value, CSV)
3891
+ * - `NULL` → `exists` with **inverted** boolean (`true` →
3892
+ * `exists=false` ⇔ IS NULL); arity- and type-checked
3893
+ *
3894
+ * `SW` (Payload has no starts-with operator) and PostgREST's
3895
+ * full-text-search operators (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
3896
+ * `UnsupportedFilterOperatorError`.
3897
+ *
3898
+ * @param filter - The operator filter to translate
3899
+ * @returns An `{ operator: value }` payload ready to merge under
3900
+ * `where[field]`
3901
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
3902
+ * exactly two values, or `NULL` does not receive exactly one boolean
3903
+ * @throws {UnsupportedFilterOperatorError} If the operator has no
3904
+ * Payload equivalent
3905
+ */
3906
+ private _formatOperatorPayload;
3907
+ }
3908
+
3909
+ /**
3910
+ * Response strategy for the Payload CMS driver
3911
+ *
3912
+ * Parses Payload's paginated collection responses — the
3913
+ * `mongoose-paginate-v2` envelope, shared by many Express/Mongoose
3914
+ * backends:
3915
+ * ```json
3916
+ * {
3917
+ * "docs": [{ "id": "abc123", "title": "Hello" }],
3918
+ * "totalDocs": 48,
3919
+ * "limit": 10,
3920
+ * "totalPages": 5,
3921
+ * "page": 2,
3922
+ * "pagingCounter": 11,
3923
+ * "hasPrevPage": true,
3924
+ * "hasNextPage": true,
3925
+ * "prevPage": 1,
3926
+ * "nextPage": 3
3927
+ * }
3928
+ * ```
3929
+ *
3930
+ * Default key paths are configured in `PayloadResponseOptions`. The
3931
+ * envelope's `pagingCounter` is the 1-indexed offset of the first doc
3932
+ * on the page, so it maps straight onto `from`; `to` is computed from
3933
+ * `page` × `limit` (clamped to the total). `prevPage` / `nextPage` are
3934
+ * **page numbers**, not URLs, so the navigation-URL slots on
3935
+ * `PaginatedCollection` stay `undefined` unless the consumer overrides
3936
+ * their paths via `IPaginationConfig`. The traversal algorithm is
3937
+ * inherited from `AbstractDotPathResponseStrategy`; this class exists
3938
+ * so `DriverEnum.PAYLOAD` resolves to a distinct identity at the DI
3939
+ * layer even though the parsing logic is shared with JSON:API, NestJS,
3940
+ * Strapi, and PocketBase.
3941
+ *
3942
+ * @see https://payloadcms.com/docs/rest-api/overview
3943
+ */
3944
+ declare class PayloadResponseStrategy extends AbstractDotPathResponseStrategy {
3945
+ }
3946
+
3947
+ /**
3948
+ * Request strategy for the PocketBase driver
3949
+ *
3950
+ * Generates URIs in [PocketBase's records-list format](https://pocketbase.io/docs/api-records/):
3951
+ * - Filters: a single `filter=(...)` expression-language parameter —
3952
+ * simple single-value filters fold to `field='value'`, multi-value
3953
+ * filters fold to an OR group (`(field='v1' || field='v2')`), and all
3954
+ * clauses join with ` && `
3955
+ * - Operator filters: expression terms (`field>=10`, `field~'val'`) —
3956
+ * see the mapping on `_formatOperatorClause`
3957
+ * - Sorts: `sort=-created,title` (CSV, `-` prefix = DESC)
3958
+ * - Field selection (flat): `fields=id,title` (CSV)
3959
+ * - Relation expansion: `expand=author,comments` (CSV)
3960
+ * - Pagination (page-based): `page=N&perPage=M`
3961
+ *
3962
+ * The `page` / `perPage` / `sort` / `filter` / `expand` / `fields` keys
3963
+ * are fixed by the PocketBase records API and intentionally not
3964
+ * configurable through `QueryBuilderOptions`; they live as private
3965
+ * statics so they are visible in one place.
3966
+ *
3967
+ * String literals are single-quoted with embedded quotes
3968
+ * backslash-escaped (`name='O\'Brien'`); numbers and booleans emit
3969
+ * bare. PocketBase has no global search param (use `~` terms instead)
3970
+ * and no per-model field selection — the corresponding fluent methods
3971
+ * throw the matching `Unsupported*Error`. The PostgREST-native
3972
+ * full-text operators (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
3973
+ * `UnsupportedFilterOperatorError`.
3974
+ *
3975
+ * @see https://pocketbase.io/docs/api-records/
3976
+ */
3977
+ declare class PocketbaseRequestStrategy extends AbstractRequestStrategy {
3978
+ /**
3979
+ * Filters, operator filters, sorts, expand (`includes`), flat field
3980
+ * selection (`select`) — no per-model fields, no global search, no
3981
+ * embedded resources
3982
+ */
3983
+ readonly capabilities: IStrategyCapabilities;
3984
+ /**
3985
+ * PocketBase-native names of the six hardcoded query keys
3986
+ *
3987
+ * The records API reads exactly these names; they are intentionally
3988
+ * not configurable through `QueryBuilderOptions` and live as private
3989
+ * statics so they are visible in one place.
3990
+ */
3991
+ private static readonly _expandKey;
3992
+ private static readonly _fieldsKey;
3993
+ private static readonly _filterKey;
3994
+ private static readonly _pageKey;
3995
+ private static readonly _perPageKey;
3996
+ private static readonly _sortKey;
3997
+ /**
3998
+ * Emit PocketBase-format query-string segments in canonical order:
3999
+ * expand → fields → filter (merged) → sort → page → perPage
4000
+ *
4001
+ * Simple filters and operator filters share the single `filter=(...)`
4002
+ * parameter so the server receives one combined expression rather
4003
+ * than two conflicting `filter` params.
4004
+ *
4005
+ * @param state - The current query builder state
4006
+ * @param _options - The query parameter key name configuration (unused;
4007
+ * PocketBase's wire keys are fixed by the server)
4008
+ * @returns Ordered query-string fragments
4009
+ */
4010
+ protected parts(state: IQueryBuilderState, _options: QueryBuilderOptions): string[];
4011
+ /**
4012
+ * Append the `expand=` CSV from the includes array
4013
+ *
4014
+ * Nested expansion (`author.address`) passes through verbatim when
4015
+ * given as a dotted include name.
4016
+ *
4017
+ * @param state - The current query builder state
4018
+ * @param out - The accumulator the caller joins into the URI
4019
+ */
4020
+ private _appendExpand;
4021
+ /**
4022
+ * Append the `fields=` CSV from the flat select array
4023
+ *
4024
+ * @param state - The current query builder state
4025
+ * @param out - The accumulator the caller joins into the URI
4026
+ */
4027
+ private _appendFields;
4028
+ /**
4029
+ * Append the single `filter=(...)` expression combining simple
4030
+ * filters and operator filters
4031
+ *
4032
+ * Clauses join with ` && `; multi-value clauses keep their own
4033
+ * parentheses so OR groups stay correctly scoped inside the AND
4034
+ * chain.
4035
+ *
4036
+ * @param state - The current query builder state
4037
+ * @param out - The accumulator the caller joins into the URI
4038
+ */
4039
+ private _appendFilter;
4040
+ /**
4041
+ * Append the `page=` / `perPage=` pagination pair
4042
+ *
4043
+ * @param state - The current query builder state
4044
+ * @param out - The accumulator the caller joins into the URI
4045
+ */
4046
+ private _appendPagination;
4047
+ /**
4048
+ * Append the `sort=-created,title` CSV parameter
4049
+ *
4050
+ * @param state - The current query builder state
4051
+ * @param out - The accumulator the caller joins into the URI
4052
+ */
4053
+ private _appendSort;
4054
+ /**
4055
+ * Translate a `FilterOperatorEnum` operator filter into one
4056
+ * PocketBase expression clause
4057
+ *
4058
+ * The mapping is library-canonical → PocketBase-native:
4059
+ * - `EQ` → `field='v'`; `GT`/`GTE`/`LT`/`LTE` → `>` / `>=` / `<` / `<=`
4060
+ * - `CONTAINS`/`ILIKE` → `field~'v'` (PocketBase's `~` is a
4061
+ * case-insensitive LIKE that auto-wraps the operand in `%...%`)
4062
+ * - `SW` → `field~'v%'` (explicit trailing wildcard disables the
4063
+ * auto-wrap)
4064
+ * - `IN` → OR group `(field='v1' || field='v2')`
4065
+ * - `BTW` → AND group `(field>=min && field<=max)` (arity-checked)
4066
+ * - `NOT` → `field!='v'` (single) / AND group of `!=` terms (multi)
4067
+ * - `NULL` → `field=null` (when value is `true`) / `field!=null`
4068
+ * (when value is `false`); arity- and type-checked
4069
+ *
4070
+ * PostgREST's full-text-search operators (`FTS`, `PHFTS`, `PLFTS`,
4071
+ * `WFTS`) have no PocketBase equivalent and throw
4072
+ * `UnsupportedFilterOperatorError`.
4073
+ *
4074
+ * @param filter - The operator filter to translate
4075
+ * @returns One expression clause ready to join into `filter=(...)`
4076
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
4077
+ * exactly two values, or `NULL` does not receive exactly one boolean
4078
+ * @throws {UnsupportedFilterOperatorError} If the operator is a
4079
+ * PostgREST-only FTS variant
4080
+ */
4081
+ private _formatOperatorClause;
4082
+ /**
4083
+ * Backslash-escape single quotes inside a string literal
4084
+ *
4085
+ * @param value - The raw string value
4086
+ * @returns The escaped string, ready to wrap in single quotes
4087
+ */
4088
+ private _escape;
4089
+ /**
4090
+ * Format a filter value as a PocketBase expression literal
4091
+ *
4092
+ * Strings are single-quoted (embedded quotes backslash-escaped);
4093
+ * numbers and booleans emit bare, matching the expression language's
4094
+ * literal rules.
4095
+ *
4096
+ * @param value - The raw filter value
4097
+ * @returns The formatted literal
4098
+ */
4099
+ private _formatValue;
4100
+ }
4101
+
4102
+ /**
4103
+ * Response strategy for the PocketBase driver
4104
+ *
4105
+ * Parses PocketBase records-list responses:
4106
+ * ```json
4107
+ * {
4108
+ * "page": 1,
4109
+ * "perPage": 30,
4110
+ * "totalItems": 48,
4111
+ * "totalPages": 2,
4112
+ * "items": [{ "id": "abc123", "title": "Hello" }]
1822
4113
  * }
1823
4114
  * ```
1824
4115
  *
1825
- * Default key paths are configured in `NestjsResponseOptions`. The
1826
- * traversal algorithm (dot-notation resolution + computed `from`/`to`) is
1827
- * inherited from `AbstractDotPathResponseStrategy`; this class exists so
1828
- * `DriverEnum.NESTJS` resolves to a distinct identity at the DI layer
1829
- * even though the parsing logic is shared with JSON:API.
4116
+ * Default key paths are configured in `PocketbaseResponseOptions`
4117
+ * all flat keys, resolved by the inherited dot-path traversal (a flat
4118
+ * key is just a one-segment path). PocketBase does not include
4119
+ * navigation links in the envelope, so `firstPageUrl`, `prevPageUrl`,
4120
+ * `nextPageUrl`, and `lastPageUrl` resolve to `undefined` unless the
4121
+ * consumer overrides their paths via `IPaginationConfig`; `from`/`to`
4122
+ * are computed from `page` × `perPage`. This class exists so
4123
+ * `DriverEnum.POCKETBASE` resolves to a distinct identity at the DI
4124
+ * layer even though the parsing logic is shared with JSON:API, NestJS,
4125
+ * and Strapi.
1830
4126
  *
1831
- * @see https://github.com/ppetzold/nestjs-paginate
4127
+ * When the request was sent with `skipTotal=1` (not emitted by this
4128
+ * driver), PocketBase reports `totalItems`/`totalPages` as `-1`;
4129
+ * override the paths or treat the values accordingly if you opt into
4130
+ * that server-side optimisation.
4131
+ *
4132
+ * @see https://pocketbase.io/docs/api-records/
1832
4133
  */
1833
- declare class NestjsResponseStrategy extends AbstractDotPathResponseStrategy {
4134
+ declare class PocketbaseResponseStrategy extends AbstractDotPathResponseStrategy {
1834
4135
  }
1835
4136
 
1836
4137
  /**
@@ -1975,10 +4276,17 @@ declare class PostgrestRequestStrategy extends AbstractRequestStrategy {
1975
4276
  */
1976
4277
  private _appendOrder;
1977
4278
  /**
1978
- * Append the select parameter as `select=col1,col2`
4279
+ * Append the select parameter as `select=col1,col2,rel(col1,col2)`
4280
+ *
4281
+ * PostgREST uses a single `select` query param for both column pruning
4282
+ * (matching NestJS semantics) and embedded-resource fetching — the
4283
+ * embedded fragments from `addEmbedded` are spliced into the same
4284
+ * param value, never emitted as a second `select`.
1979
4285
  *
1980
- * PostgREST uses a `select` query param for column pruning, matching
1981
- * NestJS semantics.
4286
+ * Fragment shape per relation: `rel(col1,col2)` with explicit columns,
4287
+ * `rel(*)` without. When embedded relations are present but no flat
4288
+ * columns were selected, the flat part defaults to `*` so the base
4289
+ * row's columns are not silently dropped from the projection.
1982
4290
  *
1983
4291
  * @param state - The current query builder state
1984
4292
  * @param options - The query parameter key name configuration
@@ -2032,6 +4340,154 @@ declare class PostgrestResponseStrategy implements IResponseStrategy {
2032
4340
  private _parseContentRange;
2033
4341
  }
2034
4342
 
4343
+ /**
4344
+ * Request strategy for the Sieve (.NET) driver
4345
+ *
4346
+ * Generates URIs in [Sieve's compact expression format](https://github.com/Biarity/Sieve):
4347
+ * - Filters: a single `filters=` parameter holding comma-joined (AND)
4348
+ * `Field{op}Value` terms; multi-value terms use the pipe (OR) on the
4349
+ * value side (`status==active|pending`)
4350
+ * - Operator filters: translated from `FilterOperatorEnum` — see the
4351
+ * mapping on `_formatOperatorTerms`
4352
+ * - Sorts: `sorts=field,-other` (CSV, `-` prefix = DESC)
4353
+ * - Pagination: `page=N&pageSize=N`
4354
+ *
4355
+ * Sieve has no per-model field selection, no relation includes, no flat
4356
+ * column selection, and no global search parameter — the corresponding
4357
+ * fluent methods throw the matching `Unsupported*Error`. PostgREST-native
4358
+ * full-text search operators (`FTS`, `PHFTS`, `PLFTS`, `WFTS`) throw
4359
+ * `UnsupportedFilterOperatorError`.
4360
+ *
4361
+ * @see https://github.com/Biarity/Sieve
4362
+ */
4363
+ declare class SieveRequestStrategy extends AbstractRequestStrategy {
4364
+ /**
4365
+ * Filters, operator filters, sorts — no per-model fields, no includes,
4366
+ * no flat select, no global search (use `CONTAINS` / `ILIKE` operator
4367
+ * filters for partial matches)
4368
+ */
4369
+ readonly capabilities: IStrategyCapabilities;
4370
+ /**
4371
+ * Sieve-native names of the three hardcoded query keys
4372
+ *
4373
+ * Sieve's model binder reads `filters`, `sorts`, and `pageSize` (the
4374
+ * plural forms differ from the library-wide `filter` / `sort` /
4375
+ * `limit` defaults); these keys are intentionally not configurable
4376
+ * through `QueryBuilderOptions` and live as private statics so they
4377
+ * are visible in one place.
4378
+ */
4379
+ private static readonly _filtersKey;
4380
+ private static readonly _pageSizeKey;
4381
+ private static readonly _sortsKey;
4382
+ /**
4383
+ * Emit Sieve-format query-string segments in canonical order:
4384
+ * filters → sorts → page → pageSize
4385
+ *
4386
+ * @param state - The current query builder state
4387
+ * @param options - The query parameter key name configuration (used
4388
+ * for `page`, whose default matches the wire format; the `filters` /
4389
+ * `sorts` / `pageSize` keys are fixed by the server)
4390
+ * @returns Ordered query-string fragments
4391
+ */
4392
+ protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
4393
+ /**
4394
+ * Append the single `filters=` parameter combining simple and operator
4395
+ * filters
4396
+ *
4397
+ * Each term is one `Field{op}Value` expression; terms join with the
4398
+ * comma (Sieve's AND). Simple single-value filters fold to `==`;
4399
+ * simple multi-value filters fold to a value-level pipe OR
4400
+ * (`field==v1|v2`).
4401
+ *
4402
+ * @param state - The current query builder state
4403
+ * @param out - The accumulator the caller joins into the URI
4404
+ */
4405
+ private _appendFilters;
4406
+ /**
4407
+ * Append the page parameter
4408
+ *
4409
+ * @param state - The current query builder state
4410
+ * @param options - The query parameter key name configuration
4411
+ * @param out - The accumulator the caller joins into the URI
4412
+ */
4413
+ private _appendPage;
4414
+ /**
4415
+ * Append the pageSize parameter
4416
+ *
4417
+ * @param state - The current query builder state
4418
+ * @param out - The accumulator the caller joins into the URI
4419
+ */
4420
+ private _appendPageSize;
4421
+ /**
4422
+ * Append the `sorts=field,-other` CSV parameter
4423
+ *
4424
+ * @param state - The current query builder state
4425
+ * @param out - The accumulator the caller joins into the URI
4426
+ */
4427
+ private _appendSorts;
4428
+ /**
4429
+ * Translate a `FilterOperatorEnum` operator filter into one or more
4430
+ * Sieve `Field{op}Value` terms
4431
+ *
4432
+ * The mapping is library-canonical → Sieve-native:
4433
+ * - `EQ` → `==`; `GT`/`GTE`/`LT`/`LTE` → `>` / `>=` / `<` / `<=`
4434
+ * - `CONTAINS` → `@=`; `ILIKE` → `@=*` (case-insensitive contains)
4435
+ * - `SW` → `_=` (starts with)
4436
+ * - `IN` → `==` with a value-level pipe OR (`field==v1|v2`)
4437
+ * - `BTW` → **two** AND-ed terms (`field>=min` and `field<=max`,
4438
+ * arity-checked)
4439
+ * - `NOT` → `!=` — one term per value, AND-ed (`field!=v1,field!=v2`)
4440
+ * - `NULL` → `==null` (when value is `true`) / `!=null` (when value is
4441
+ * `false`); arity- and type-checked
4442
+ *
4443
+ * PostgREST's full-text-search operators (`FTS`, `PHFTS`, `PLFTS`,
4444
+ * `WFTS`) have no Sieve equivalent and throw
4445
+ * `UnsupportedFilterOperatorError`.
4446
+ *
4447
+ * @param filter - The operator filter to translate
4448
+ * @returns One or more `Field{op}Value` terms ready to AND-join
4449
+ * @throws {InvalidFilterOperatorValueError} If `BTW` does not receive
4450
+ * exactly two values, or `NULL` does not receive exactly one boolean
4451
+ * @throws {UnsupportedFilterOperatorError} If the operator is a
4452
+ * PostgREST-only FTS variant
4453
+ */
4454
+ private _formatOperatorTerms;
4455
+ }
4456
+
4457
+ /**
4458
+ * Response strategy for the Sieve (.NET) driver
4459
+ *
4460
+ * Sieve itself does not define a response envelope — it returns an
4461
+ * `IQueryable` that the ASP.NET developer wraps in a paging DTO of their
4462
+ * choosing. This strategy therefore ships a **sensible default mapping**
4463
+ * for the common hand-rolled `PagedResult<T>` shape:
4464
+ * ```json
4465
+ * {
4466
+ * "data": [{ "id": 1, "title": "Hello" }],
4467
+ * "page": 2,
4468
+ * "pageSize": 10,
4469
+ * "total": 48,
4470
+ * "totalPages": 5
4471
+ * }
4472
+ * ```
4473
+ *
4474
+ * Every key path is configurable through `IConfig.response` (dot
4475
+ * notation supported), so any wrapper shape — `{ items, meta: {...} }`,
4476
+ * `{ results, pagination: {...} }` — can be mapped without subclassing.
4477
+ * Defaults are encoded in `SieveResponseOptions`. `from`/`to` are
4478
+ * computed from `page` × `pageSize` by the inherited traversal
4479
+ * algorithm, and the navigation-URL slots resolve to `undefined` unless
4480
+ * paths are provided.
4481
+ *
4482
+ * The dot-notation traversal is inherited from
4483
+ * `AbstractDotPathResponseStrategy`; this class exists so
4484
+ * `DriverEnum.SIEVE` resolves to a distinct identity at the DI layer.
4485
+ *
4486
+ * @see https://github.com/Biarity/Sieve
4487
+ */
4488
+ declare class SieveResponseStrategy extends AbstractDotPathResponseStrategy {
4489
+ }
4490
+
2035
4491
  /**
2036
4492
  * Request strategy for the Spatie Query Builder driver
2037
4493
  *
@@ -2141,6 +4597,155 @@ declare class SpatieRequestStrategy extends AbstractRequestStrategy {
2141
4597
  declare class SpatieResponseStrategy extends AbstractFlatResponseStrategy {
2142
4598
  }
2143
4599
 
4600
+ /**
4601
+ * Request strategy for the Spring Data REST driver
4602
+ *
4603
+ * Generates URIs in [Spring Data REST's pagination format](https://docs.spring.io/spring-data/rest/reference/paging-and-sorting.html):
4604
+ * - Sorts: `sort=field,asc&sort=other,desc` (repeatable param, one per rule)
4605
+ * - Pagination: `page=N&size=N` — **`page` is 0-indexed on the wire**;
4606
+ * the library state stays 1-indexed and the strategy subtracts 1 at
4607
+ * emission time
4608
+ *
4609
+ * Spring Data REST defines no standard query parameter convention for
4610
+ * filtering, field selection, includes, or global search — those are
4611
+ * implemented server-side via custom query methods or Specifications.
4612
+ * The corresponding fluent methods (`addFilter`, `addFilterOperator`,
4613
+ * `addSelect`, `addFields`, `addIncludes`, `setSearch`) throw the
4614
+ * matching `Unsupported*Error` on this driver.
4615
+ *
4616
+ * @see https://docs.spring.io/spring-data/rest/reference/paging-and-sorting.html
4617
+ */
4618
+ declare class SpringRequestStrategy extends AbstractRequestStrategy {
4619
+ /**
4620
+ * Sorts only — Spring Data REST has no standard wire convention for
4621
+ * filters, operator filters, per-model fields, flat select, includes,
4622
+ * or global search
4623
+ */
4624
+ readonly capabilities: IStrategyCapabilities;
4625
+ /**
4626
+ * Spring-native name of the hardcoded page-size query key
4627
+ *
4628
+ * The wire format is fixed (Spring's `PageableHandlerMethodArgumentResolver`
4629
+ * reads `size` by default); the key is intentionally not configurable
4630
+ * through `QueryBuilderOptions` and lives as a private static so it is
4631
+ * visible in one place.
4632
+ */
4633
+ private static readonly _sizeKey;
4634
+ /**
4635
+ * Emit Spring-format query-string segments in canonical order:
4636
+ * sort → page → size
4637
+ *
4638
+ * @param state - The current query builder state
4639
+ * @param options - The query parameter key name configuration (used
4640
+ * for `page` and `sort`, whose defaults match the wire format; the
4641
+ * `size` key is fixed by the server)
4642
+ * @returns Ordered query-string fragments
4643
+ */
4644
+ protected parts(state: IQueryBuilderState, options: QueryBuilderOptions): string[];
4645
+ /**
4646
+ * Append the 0-indexed page parameter
4647
+ *
4648
+ * The library state is 1-indexed (page 1 is the first page); Spring's
4649
+ * `page` request parameter is 0-indexed, so the strategy subtracts 1
4650
+ * at emission time.
4651
+ *
4652
+ * @param state - The current query builder state
4653
+ * @param options - The query parameter key name configuration
4654
+ * @param out - The accumulator the caller joins into the URI
4655
+ */
4656
+ private _appendPage;
4657
+ /**
4658
+ * Append the size parameter
4659
+ *
4660
+ * @param state - The current query builder state
4661
+ * @param out - The accumulator the caller joins into the URI
4662
+ */
4663
+ private _appendSize;
4664
+ /**
4665
+ * Append `sort=field,asc` params, one per sort rule (repeatable)
4666
+ *
4667
+ * Spring parses each `sort` occurrence independently — multiple rules
4668
+ * are expressed by repeating the parameter, not by comma-joining the
4669
+ * fields.
4670
+ *
4671
+ * @param state - The current query builder state
4672
+ * @param options - The query parameter key name configuration
4673
+ * @param out - The accumulator the caller joins into the URI
4674
+ */
4675
+ private _appendSort;
4676
+ }
4677
+
4678
+ /**
4679
+ * Response strategy for the Spring Data REST driver
4680
+ *
4681
+ * Parses Spring Data REST's HAL envelope:
4682
+ * ```json
4683
+ * {
4684
+ * "_embedded": { "users": [{ "id": 1, "name": "John" }] },
4685
+ * "_links": {
4686
+ * "first": { "href": "..." },
4687
+ * "prev": { "href": "..." },
4688
+ * "next": { "href": "..." },
4689
+ * "last": { "href": "..." }
4690
+ * },
4691
+ * "page": { "size": 20, "totalElements": 100, "totalPages": 5, "number": 1 }
4692
+ * }
4693
+ * ```
4694
+ *
4695
+ * Two HAL quirks are absorbed here on top of the inherited dot-path
4696
+ * traversal:
4697
+ *
4698
+ * - **`page.number` is 0-indexed** — the strategy adds 1 so the library
4699
+ * state stays 1-indexed (mirroring `SpringRequestStrategy`, which
4700
+ * subtracts 1 on the way out).
4701
+ * - **The collection key under `_embedded` is the resource rel name**
4702
+ * (e.g. `_embedded.users`), which cannot be known statically. The
4703
+ * default `data` path is plain `_embedded`; when it resolves to an
4704
+ * object rather than an array, the strategy picks the first array
4705
+ * value inside it. Consumers with multiple embedded rels can pin the
4706
+ * exact path via `IConfig.response` (e.g. `data: '_embedded.users'`).
4707
+ *
4708
+ * Default key paths are configured in `SpringResponseOptions`.
4709
+ *
4710
+ * @see https://docs.spring.io/spring-data/rest/reference/paging-and-sorting.html
4711
+ */
4712
+ declare class SpringResponseStrategy extends AbstractDotPathResponseStrategy {
4713
+ /**
4714
+ * Parse a Spring Data REST HAL response into a PaginatedCollection
4715
+ *
4716
+ * @param response - The raw API response body
4717
+ * @param options - The response key name configuration
4718
+ * @returns A typed PaginatedCollection instance
4719
+ */
4720
+ paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
4721
+ /**
4722
+ * Resolve the 1-indexed current page from the 0-indexed `page.number`
4723
+ *
4724
+ * Falls back to page 1 when the path is missing entirely (defensive —
4725
+ * Spring always emits the `page` block on paged endpoints).
4726
+ *
4727
+ * @param response - The raw response object
4728
+ * @param options - The response key name configuration
4729
+ * @returns The 1-indexed current page number
4730
+ */
4731
+ private _resolveCurrentPage;
4732
+ /**
4733
+ * Resolve the data array from the HAL `_embedded` wrapper
4734
+ *
4735
+ * When the configured path resolves directly to an array (a consumer
4736
+ * pinned `data: '_embedded.users'`), it is used as-is. When it
4737
+ * resolves to an object (the default `_embedded` path), the first
4738
+ * array value inside it is used — Spring emits exactly one collection
4739
+ * rel per listing endpoint. An empty array is returned when nothing
4740
+ * matches (e.g. Spring omits `_embedded` on empty result sets).
4741
+ *
4742
+ * @param response - The raw response object
4743
+ * @param options - The response key name configuration
4744
+ * @returns The resolved data array (possibly empty)
4745
+ */
4746
+ private _resolveData;
4747
+ }
4748
+
2144
4749
  /**
2145
4750
  * Request strategy for the Strapi driver
2146
4751
  *
@@ -2309,5 +4914,241 @@ declare class StrapiRequestStrategy extends AbstractRequestStrategy {
2309
4914
  declare class StrapiResponseStrategy extends AbstractDotPathResponseStrategy {
2310
4915
  }
2311
4916
 
2312
- export { DriverEnum, FilterOperatorEnum, InvalidFilterOperatorValueError, InvalidLimitError, InvalidPageNumberError, InvalidResourceNameError, JsonApiRequestStrategy, JsonApiResponseStrategy, KeyNotFoundError, LaravelRequestStrategy, LaravelResponseStrategy, NG_QUBEE_DRIVER, NG_QUBEE_REQUEST_OPTIONS, NG_QUBEE_REQUEST_STRATEGY, NG_QUBEE_RESPONSE_OPTIONS, NG_QUBEE_RESPONSE_STRATEGY, NestjsRequestStrategy, NestjsResponseStrategy, NgQubeeModule, NgQubeeService, PaginatedCollection, PaginationModeEnum, PaginationNotSyncedError, PaginationService, PostgrestRequestStrategy, PostgrestResponseStrategy, SortEnum, SpatieRequestStrategy, SpatieResponseStrategy, StrapiRequestStrategy, StrapiResponseStrategy, UnselectableModelError, UnsupportedFieldSelectionError, UnsupportedFilterError, UnsupportedFilterOperatorError, UnsupportedIncludesError, UnsupportedSearchError, UnsupportedSelectError, UnsupportedSortError, buildNgQubeeProviders, provideNgQubee, provideNgQubeeInstance, readHeader };
2313
- export type { HeaderBag, IConfig, IFields, IFilters, INestState, IOperatorFilter, IPage, IPaginatedObject, IPaginationConfig, IQueryBuilderConfig, IQueryBuilderState, IRequestStrategy, IResponseStrategy, ISort };
4917
+ /**
4918
+ * Request strategy for the WordPress REST API driver
4919
+ *
4920
+ * Generates URIs in the [WordPress REST API collection format](https://developer.wordpress.org/rest-api/using-the-rest-api/pagination/):
4921
+ * - Filters: `field=value` (collection parameters like `status`,
4922
+ * `author`, `categories`); multi-value folds to a CSV (`field=v1,v2`,
4923
+ * the list convention WordPress uses for ID params)
4924
+ * - Sorts: `orderby=field&order=asc|desc` — WordPress core supports a
4925
+ * **single** orderby, so only the first sort rule is emitted
4926
+ * - Field selection (flat): `_fields=id,title` (CSV)
4927
+ * - Relation embedding: `_embed=author,wp:term` (CSV)
4928
+ * - Search: `search=term`
4929
+ * - Pagination (page-based): `page=N&per_page=M`
4930
+ *
4931
+ * The `page` / `per_page` / `orderby` / `order` / `search` and the
4932
+ * underscore-prefixed global params (`_fields`, `_embed`) are fixed by
4933
+ * the server and intentionally not configurable through
4934
+ * `QueryBuilderOptions`; they live as private statics so they are
4935
+ * visible in one place.
4936
+ *
4937
+ * WordPress caps `per_page` at **100** server-side (a 400
4938
+ * `rest_invalid_param` response beyond that); the cap is endpoint
4939
+ * policy rather than a syntax rule, so `validateLimit` keeps the
4940
+ * default positive-integer check and the server stays authoritative.
4941
+ * There is no generic comparison-operator syntax (only
4942
+ * parameter-specific helpers like `before`/`after` for dates, which
4943
+ * pass through `addFilter`), so `addFilterOperator` throws
4944
+ * `UnsupportedFilterOperatorError` via the capability gate.
4945
+ *
4946
+ * @see https://developer.wordpress.org/rest-api/reference/posts/#list-posts
4947
+ */
4948
+ declare class WordpressRequestStrategy extends AbstractRequestStrategy {
4949
+ /**
4950
+ * Filters, sorts, global search, flat field selection (`select`),
4951
+ * embedding (`includes`) — no operator filters, no per-model fields,
4952
+ * no embedded-column projection
4953
+ */
4954
+ readonly capabilities: IStrategyCapabilities;
4955
+ /**
4956
+ * WordPress-native names of the seven hardcoded query keys
4957
+ *
4958
+ * The underscore prefix marks the REST API's global params apart
4959
+ * from collection filters; all keys are fixed by the server and
4960
+ * intentionally not configurable through `QueryBuilderOptions`.
4961
+ */
4962
+ private static readonly _embedKey;
4963
+ private static readonly _fieldsKey;
4964
+ private static readonly _orderbyKey;
4965
+ private static readonly _orderKey;
4966
+ private static readonly _pageKey;
4967
+ private static readonly _perPageKey;
4968
+ private static readonly _searchKey;
4969
+ /**
4970
+ * Emit WordPress-format query-string segments in canonical order:
4971
+ * filters → orderby/order → _fields → _embed → search → page → per_page
4972
+ *
4973
+ * @param state - The current query builder state
4974
+ * @param _options - The query parameter key name configuration (unused;
4975
+ * WordPress' wire keys are fixed by the server)
4976
+ * @returns Ordered query-string fragments
4977
+ */
4978
+ protected parts(state: IQueryBuilderState, _options: QueryBuilderOptions): string[];
4979
+ /**
4980
+ * Append the `_embed=` CSV from the includes array
4981
+ *
4982
+ * A bare `_embed` (no value) embeds everything; this driver always
4983
+ * emits the named form so the response stays lean.
4984
+ *
4985
+ * @param state - The current query builder state
4986
+ * @param out - The accumulator the caller joins into the URI
4987
+ */
4988
+ private _appendEmbed;
4989
+ /**
4990
+ * Append the `_fields=` CSV from the flat select array
4991
+ *
4992
+ * @param state - The current query builder state
4993
+ * @param out - The accumulator the caller joins into the URI
4994
+ */
4995
+ private _appendFields;
4996
+ /**
4997
+ * Append simple filter parameters
4998
+ *
4999
+ * A single value emits the bare form (`status=publish`); multiple
5000
+ * values fold to the CSV list convention (`categories=2,3`).
5001
+ *
5002
+ * @param state - The current query builder state
5003
+ * @param out - The accumulator the caller joins into the URI
5004
+ */
5005
+ private _appendFilters;
5006
+ /**
5007
+ * Append the `page=` / `per_page=` pagination pair
5008
+ *
5009
+ * @param state - The current query builder state
5010
+ * @param out - The accumulator the caller joins into the URI
5011
+ */
5012
+ private _appendPagination;
5013
+ /**
5014
+ * Append the `search=` parameter
5015
+ *
5016
+ * @param state - The current query builder state
5017
+ * @param out - The accumulator the caller joins into the URI
5018
+ */
5019
+ private _appendSearch;
5020
+ /**
5021
+ * Append the `orderby=` / `order=` pair from the first sort rule
5022
+ *
5023
+ * WordPress core accepts a single `orderby` value — additional sort
5024
+ * rules in state are ignored by design (the server would reject a
5025
+ * CSV here).
5026
+ *
5027
+ * @param state - The current query builder state
5028
+ * @param out - The accumulator the caller joins into the URI
5029
+ */
5030
+ private _appendSort;
5031
+ }
5032
+
5033
+ /**
5034
+ * Response strategy for the WordPress REST API driver
5035
+ *
5036
+ * WordPress returns a bare array body for collection endpoints.
5037
+ * Pagination metadata travels in HTTP response headers:
5038
+ *
5039
+ * - `X-WP-Total` — total number of records in the collection
5040
+ * - `X-WP-TotalPages` — total number of pages at the requested
5041
+ * `per_page`
5042
+ * - `Link` — RFC 5988 navigation links (`rel="next"` / `rel="prev"`)
5043
+ *
5044
+ * The strategy surfaces the `Link` URLs as `nextPageUrl` /
5045
+ * `prevPageUrl` and derives position from them:
5046
+ *
5047
+ * - `currentPage` is the `prev` link's `page` param + 1 (no `prev` →
5048
+ * page **1**), falling back to the `next` link's `page` param − 1.
5049
+ * - `perPage` is the item count of the current page whenever a `next`
5050
+ * link exists (a page with a successor is necessarily full); on the
5051
+ * last page of a multi-page set it is not introspectable and stays
5052
+ * `undefined`.
5053
+ * - `from`/`to` derive from `currentPage` × `perPage` on full pages,
5054
+ * or count back from the total on the last page
5055
+ * (`from = total - data.length + 1`, `to = total`).
5056
+ *
5057
+ * This strategy expects the consumer to pass the array body as
5058
+ * `response` (or a plain object with `response[options.data]` pointing
5059
+ * at the array) and the response headers via the optional `headers`
5060
+ * bag — the same call-site shape as the PostgREST driver. Omitted
5061
+ * headers are tolerated and yield a collection with `undefined`
5062
+ * bounds.
5063
+ *
5064
+ * @see https://developer.wordpress.org/rest-api/using-the-rest-api/pagination/
5065
+ */
5066
+ declare class WordpressResponseStrategy implements IResponseStrategy {
5067
+ private static readonly _linkHeader;
5068
+ private static readonly _linkRegex;
5069
+ private static readonly _pageParamRegex;
5070
+ private static readonly _totalHeader;
5071
+ private static readonly _totalPagesHeader;
5072
+ /**
5073
+ * Parse a WordPress REST response into a typed PaginatedCollection
5074
+ *
5075
+ * @param response - The raw response. Either the array body directly, or
5076
+ * an object with the array at `response[options.data]`.
5077
+ * @param options - The response key configuration (only `options.data` is
5078
+ * consulted; all pagination metadata comes from headers).
5079
+ * @param headers - Optional HTTP response headers. `X-WP-Total` /
5080
+ * `X-WP-TotalPages` drive the totals and the `Link` header drives
5081
+ * navigation and page derivation; omission is tolerated.
5082
+ * @returns A typed PaginatedCollection instance
5083
+ */
5084
+ paginate<T extends IPaginatedObject>(response: Record<string, unknown>, options: ResponseOptions, headers?: HeaderBag): PaginatedCollection<T>;
5085
+ /**
5086
+ * Derive the current page from the Link relations
5087
+ *
5088
+ * The `prev` URL's `page` param + 1 is authoritative; without a
5089
+ * `prev` the page is 1 unless a `next` URL contradicts it (its page
5090
+ * param − 1). A missing/unparseable Link header yields page 1.
5091
+ *
5092
+ * @param next - The `rel="next"` URL, if present
5093
+ * @param prev - The `rel="prev"` URL, if present
5094
+ * @returns The 1-indexed current page
5095
+ */
5096
+ private _deriveCurrentPage;
5097
+ /**
5098
+ * Derive `from` as the 1-indexed offset of the first item on this page
5099
+ *
5100
+ * Computed from `currentPage` × `perPage` on full pages; on the last
5101
+ * page (no `next` link) it counts back from the total
5102
+ * (`total - items + 1`), which also covers single-page responses.
5103
+ *
5104
+ * @param data - The items on the current page
5105
+ * @param currentPage - The current page number
5106
+ * @param next - The `rel="next"` URL, if present
5107
+ * @param perPage - The page size (may be undefined)
5108
+ * @param total - The total item count (may be undefined)
5109
+ * @returns The 1-indexed `from` index, or undefined when inputs insufficient
5110
+ */
5111
+ private _deriveFrom;
5112
+ /**
5113
+ * Derive `to` as the 1-indexed offset of the last item on this page
5114
+ *
5115
+ * Clamped to `total` so the last page does not report past the end;
5116
+ * on the last page (no `next` link) it is simply the total.
5117
+ *
5118
+ * @param data - The items on the current page
5119
+ * @param currentPage - The current page number
5120
+ * @param next - The `rel="next"` URL, if present
5121
+ * @param perPage - The page size (may be undefined)
5122
+ * @param total - The total item count (may be undefined)
5123
+ * @returns The 1-indexed `to` index, or undefined when inputs insufficient
5124
+ */
5125
+ private _deriveTo;
5126
+ /**
5127
+ * Extract the `page` query param from a navigation URL
5128
+ *
5129
+ * @param url - The URL to inspect (possibly undefined)
5130
+ * @returns The parsed page number, or undefined
5131
+ */
5132
+ private _pageParam;
5133
+ /**
5134
+ * Parse a non-negative integer count header value
5135
+ *
5136
+ * @param value - Raw header value (possibly null/undefined)
5137
+ * @returns The parsed count, or undefined when absent or unparseable
5138
+ */
5139
+ private _parseCount;
5140
+ /**
5141
+ * Extract the `rel="next"` / `rel="prev"` URLs from an RFC 5988
5142
+ * `Link` header value
5143
+ *
5144
+ * Tolerates any ordering, extra relations (`rel="collection"` etc.
5145
+ * are ignored), and a missing header.
5146
+ *
5147
+ * @param value - Raw header value (possibly null/undefined)
5148
+ * @returns The navigation URLs found, keyed by relation
5149
+ */
5150
+ private _parseLinkHeader;
5151
+ }
5152
+
5153
+ export { ApiPlatformRequestStrategy, ApiPlatformResponseOptions, ApiPlatformResponseStrategy, DirectusRequestStrategy, DirectusResponseOptions, DirectusResponseStrategy, DrfRequestStrategy, DrfResponseOptions, DrfResponseStrategy, DriverEnum, FeathersRequestStrategy, FeathersResponseOptions, FeathersResponseStrategy, FilterOperatorEnum, InvalidFilterOperatorValueError, InvalidLimitError, InvalidPageNumberError, InvalidResourceNameError, JsonApiRequestStrategy, JsonApiResponseOptions, JsonApiResponseStrategy, JsonServerRequestStrategy, JsonServerResponseOptions, JsonServerResponseStrategy, KeyNotFoundError, LaravelRequestStrategy, LaravelResponseStrategy, NG_QUBEE_DRIVER, NG_QUBEE_REQUEST_OPTIONS, NG_QUBEE_REQUEST_STRATEGY, NG_QUBEE_RESPONSE_OPTIONS, NG_QUBEE_RESPONSE_STRATEGY, NestjsRequestStrategy, NestjsResponseOptions, NestjsResponseStrategy, NestjsxCrudRequestStrategy, NestjsxCrudResponseOptions, NestjsxCrudResponseStrategy, NgQubeeModule, NgQubeeService, OdataRequestStrategy, OdataResponseOptions, OdataResponseStrategy, PaginatedCollection, PaginationModeEnum, PaginationNotSyncedError, PaginationService, PayloadRequestStrategy, PayloadResponseOptions, PayloadResponseStrategy, PocketbaseRequestStrategy, PocketbaseResponseOptions, PocketbaseResponseStrategy, PostgrestRequestStrategy, PostgrestResponseStrategy, QueryBuilderOptions, ResponseOptions, SieveRequestStrategy, SieveResponseOptions, SieveResponseStrategy, SortEnum, SpatieRequestStrategy, SpatieResponseStrategy, SpringRequestStrategy, SpringResponseOptions, SpringResponseStrategy, StrapiRequestStrategy, StrapiResponseOptions, StrapiResponseStrategy, UnselectableModelError, UnsupportedEmbeddedError, UnsupportedFieldSelectionError, UnsupportedFilterError, UnsupportedFilterOperatorError, UnsupportedIncludesError, UnsupportedSearchError, UnsupportedSelectError, UnsupportedSortError, WordpressRequestStrategy, WordpressResponseStrategy, buildNgQubeeProviders, provideNgQubee, provideNgQubeeInstance, readHeader };
5154
+ export type { Embedded, HeaderBag, IConfig, IFields, IFilters, INestState, IOperatorFilter, IPage, IPaginatedObject, IPaginationConfig, IQueryBuilderConfig, IQueryBuilderState, IRequestStrategy, IResponseStrategy, ISort };