ng-qubee 3.0.0 → 3.2.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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { ModuleWithProviders, EnvironmentProviders, Signal } from '@angular/core';
2
+ import { ModuleWithProviders, Provider, EnvironmentProviders, Signal, InjectionToken } from '@angular/core';
3
3
  import { Observable } from 'rxjs';
4
4
 
5
5
  interface INormalized {
@@ -46,6 +46,7 @@ declare class PaginatedCollection<T extends IPaginatedObject> {
46
46
  * request building (URI generation) and response parsing.
47
47
  */
48
48
  declare enum DriverEnum {
49
+ JSON_API = "json-api",
49
50
  LARAVEL = "laravel",
50
51
  NESTJS = "nestjs",
51
52
  SPATIE = "spatie"
@@ -153,6 +154,18 @@ declare class NgQubeeModule {
153
154
  static ɵinj: i0.ɵɵInjectorDeclaration<NgQubeeModule>;
154
155
  }
155
156
 
157
+ /**
158
+ * Build the core provider list shared by `provideNgQubee()` and
159
+ * `NgQubeeModule.forRoot()`
160
+ *
161
+ * Exposes the driver, strategies, and options via injection tokens so that
162
+ * consumers can request a component-scoped instance of the services through
163
+ * `provideNgQubeeInstance()`.
164
+ *
165
+ * @param config - Configuration object compliant to the IConfig interface
166
+ * @returns An array of Providers for the environment injector
167
+ */
168
+ declare function buildNgQubeeProviders(config: IConfig): Provider[];
156
169
  /**
157
170
  * Sets up providers necessary to enable `NgQubee` functionality for the application.
158
171
  *
@@ -174,6 +187,15 @@ declare class NgQubeeModule {
174
187
  * });
175
188
  * ```
176
189
  *
190
+ * JSON:API driver example:
191
+ * ```
192
+ * import { DriverEnum } from 'ng-qubee';
193
+ *
194
+ * bootstrapApplication(AppComponent, {
195
+ * providers: [provideNgQubee({ driver: DriverEnum.JSON_API })]
196
+ * });
197
+ * ```
198
+ *
177
199
  * NestJS driver example:
178
200
  * ```
179
201
  * import { DriverEnum } from 'ng-qubee';
@@ -188,6 +210,34 @@ declare class NgQubeeModule {
188
210
  * @returns A set of providers to setup NgQubee
189
211
  */
190
212
  declare function provideNgQubee(config: IConfig): EnvironmentProviders;
213
+ /**
214
+ * Providers for a component-scoped NgQubee instance
215
+ *
216
+ * Use this inside a standalone component's `providers: [...]` to get a
217
+ * dedicated `NgQubeeService` (and its `NestService` / `PaginationService`
218
+ * collaborators) whose query-builder and pagination state does not bleed
219
+ * with the app-wide shared instance provided by `provideNgQubee()`.
220
+ *
221
+ * @usageNotes
222
+ *
223
+ * ```
224
+ * @Component({
225
+ * standalone: true,
226
+ * providers: [...provideNgQubeeInstance()]
227
+ * })
228
+ * export class MyFeatureComponent {
229
+ * constructor(private _qb: NgQubeeService) {}
230
+ * }
231
+ * ```
232
+ *
233
+ * The driver, strategies, and options are inherited from the environment
234
+ * injector (`provideNgQubee()` at root), so only the service instances are
235
+ * re-created at the component level.
236
+ *
237
+ * @publicApi
238
+ * @returns A provider array to spread into a component's `providers`
239
+ */
240
+ declare function provideNgQubeeInstance(): Provider[];
191
241
 
192
242
  /**
193
243
  * Enum representing the available filter operators for the NestJS driver
@@ -270,6 +320,10 @@ interface IQueryBuilderState {
270
320
  filters: IFilters;
271
321
  /** Related models to include (Spatie only) */
272
322
  includes: string[];
323
+ /** Whether the last paginated response has synced `lastPage` into state */
324
+ isLastPageKnown: boolean;
325
+ /** Last page number known from the most recent paginated response; only meaningful when `isLastPageKnown` is true */
326
+ lastPage: number;
273
327
  /** Number of items per page (all drivers) */
274
328
  limit: number;
275
329
  /** Filters with explicit operators (NestJS only) */
@@ -321,6 +375,17 @@ interface IRequestStrategy {
321
375
  * @returns The composed URI string
322
376
  */
323
377
  buildUri(state: IQueryBuilderState, options: QueryBuilderOptions): string;
378
+ /**
379
+ * Assert that the given limit value is valid for this driver
380
+ *
381
+ * Validation is driver-scoped because the accepted range differs by
382
+ * backend: nestjs-paginate treats `-1` as a "fetch all" sentinel, while
383
+ * other backends (Laravel, Spatie, JSON:API) require a positive integer.
384
+ *
385
+ * @param limit - The limit value to validate
386
+ * @throws {import('../errors/invalid-limit.error').InvalidLimitError} If the value is not accepted by the driver
387
+ */
388
+ validateLimit(limit: number): void;
324
389
  }
325
390
 
326
391
  declare class NestService {
@@ -347,10 +412,13 @@ declare class NestService {
347
412
  set baseUrl(baseUrl: string);
348
413
  /**
349
414
  * Set the limit for paginated results
350
- * Must be a positive integer greater than 0
415
+ *
416
+ * This setter performs a raw state write. Validation of the value is the
417
+ * responsibility of the active request strategy and is enforced upstream
418
+ * by `NgQubeeService.setLimit()`, because the accepted range depends on
419
+ * the driver (e.g. nestjs-paginate accepts `-1` for "fetch all").
351
420
  *
352
421
  * @param {number} limit - The number of items per page
353
- * @throws {InvalidLimitError} If limit is not a positive integer
354
422
  * @example
355
423
  * service.limit = 25;
356
424
  */
@@ -376,14 +444,6 @@ declare class NestService {
376
444
  */
377
445
  set resource(resource: string);
378
446
  private _clone;
379
- /**
380
- * Validates that the limit is a positive integer
381
- *
382
- * @param {number} limit - The limit value to validate
383
- * @throws {InvalidLimitError} If limit is not a positive integer
384
- * @private
385
- */
386
- private _validateLimit;
387
447
  /**
388
448
  * Validates that the page number is a positive integer
389
449
  *
@@ -544,6 +604,19 @@ declare class NestService {
544
604
  * service.setSearch('john doe');
545
605
  */
546
606
  setSearch(search: string): void;
607
+ /**
608
+ * Atomically record the `lastPage` value from a paginated response and
609
+ * flip `isLastPageKnown` to `true`
610
+ *
611
+ * Called exclusively by `PaginationService.paginate()` as part of the
612
+ * auto-sync contract; not intended to be invoked by consumers directly.
613
+ * Keeping the two fields under a single write guarantees they cannot
614
+ * drift out of sync.
615
+ *
616
+ * @param {number} lastPage - The last page number parsed from the most recent paginated response
617
+ * @return {void}
618
+ */
619
+ syncLastPage(lastPage: number): void;
547
620
  /**
548
621
  * Reset the query builder state to initial values
549
622
  * Clears all fields, filters, includes, sorts, and resets pagination
@@ -579,7 +652,7 @@ declare class NgQubeeService {
579
652
  * Observable that emits non-empty generated URIs
580
653
  */
581
654
  uri$: Observable<string>;
582
- constructor(_nestService: NestService, requestStrategy: IRequestStrategy, driver: DriverEnum, options?: IQueryBuilderConfig);
655
+ constructor(_nestService: NestService, requestStrategy: IRequestStrategy, driver: DriverEnum, options?: QueryBuilderOptions);
583
656
  /**
584
657
  * Assert that the active driver is one of the allowed drivers
585
658
  *
@@ -589,7 +662,7 @@ declare class NgQubeeService {
589
662
  */
590
663
  private _assertDriver;
591
664
  /**
592
- * Add fields to the select statement for the given model (Spatie only)
665
+ * Add fields to the select statement for the given model (JSON:API and Spatie only)
593
666
  *
594
667
  * @param model - Model that holds the fields
595
668
  * @param fields - Fields to select
@@ -598,9 +671,9 @@ declare class NgQubeeService {
598
671
  */
599
672
  addFields(model: string, fields: string[]): this;
600
673
  /**
601
- * Add a filter with the given value(s) (Spatie and NestJS only)
674
+ * Add a filter with the given value(s) (JSON:API, NestJS, and Spatie)
602
675
  *
603
- * Produces: `filter[field]=value` (Spatie) or `filter.field=value` (NestJS)
676
+ * Produces: `filter[field]=value` (JSON:API / Spatie) or `filter.field=value` (NestJS)
604
677
  *
605
678
  * @param {string} field - Name of the field to filter
606
679
  * @param {(string | number | boolean)[]} values - The needle(s)
@@ -621,7 +694,7 @@ declare class NgQubeeService {
621
694
  */
622
695
  addFilterOperator(field: string, operator: FilterOperatorEnum, ...values: (string | number | boolean)[]): this;
623
696
  /**
624
- * Add related entities to include in the request (Spatie only)
697
+ * Add related entities to include in the request (JSON:API and Spatie only)
625
698
  *
626
699
  * @param {string[]} models - Models to include
627
700
  * @returns {this}
@@ -639,7 +712,7 @@ declare class NgQubeeService {
639
712
  */
640
713
  addSelect(...fields: string[]): this;
641
714
  /**
642
- * Add a field with a sort criteria (Spatie and NestJS only)
715
+ * Add a field with a sort criteria (JSON:API, NestJS, and Spatie)
643
716
  *
644
717
  * @param field - Field to use for sorting
645
718
  * @param {SortEnum} order - A value from the SortEnum enumeration
@@ -648,7 +721,14 @@ declare class NgQubeeService {
648
721
  */
649
722
  addSort(field: string, order: SortEnum): this;
650
723
  /**
651
- * Delete selected fields for the given models in the current query builder state (Spatie only)
724
+ * Get the current page number
725
+ *
726
+ * @remarks Always safe to call. Thin accessor over the internal state's `page` field.
727
+ * @returns The current page number
728
+ */
729
+ currentPage(): number;
730
+ /**
731
+ * Delete selected fields for the given models in the current query builder state (JSON:API and Spatie only)
652
732
  *
653
733
  * ```
654
734
  * ngQubeeService.deleteFields({
@@ -663,7 +743,7 @@ declare class NgQubeeService {
663
743
  */
664
744
  deleteFields(fields: IFields): this;
665
745
  /**
666
- * Delete selected fields for the given model in the current query builder state (Spatie only)
746
+ * Delete selected fields for the given model in the current query builder state (JSON:API and Spatie only)
667
747
  *
668
748
  * ```
669
749
  * ngQubeeService.deleteFieldsByModel('users', 'email', 'password');
@@ -676,7 +756,7 @@ declare class NgQubeeService {
676
756
  */
677
757
  deleteFieldsByModel(model: string, ...fields: string[]): this;
678
758
  /**
679
- * Remove given filters from the query builder state (Spatie and NestJS only)
759
+ * Remove given filters from the query builder state (JSON:API, NestJS, and Spatie)
680
760
  *
681
761
  * @param {string[]} filters - Filters to remove
682
762
  * @returns {this}
@@ -684,7 +764,7 @@ declare class NgQubeeService {
684
764
  */
685
765
  deleteFilters(...filters: string[]): this;
686
766
  /**
687
- * Remove selected related models from the query builder state (Spatie only)
767
+ * Remove selected related models from the query builder state (JSON:API and Spatie only)
688
768
  *
689
769
  * @param {string[]} includes - Models to remove
690
770
  * @returns {this}
@@ -715,19 +795,88 @@ declare class NgQubeeService {
715
795
  */
716
796
  deleteSelect(...fields: string[]): this;
717
797
  /**
718
- * Remove sort rules from the query builder state (Spatie and NestJS only)
798
+ * Remove sort rules from the query builder state (JSON:API, NestJS, and Spatie)
719
799
  *
720
800
  * @param sorts - Fields used for sorting to remove
721
801
  * @returns {this}
722
802
  * @throws {UnsupportedSortError} If the active driver does not support sorts
723
803
  */
724
804
  deleteSorts(...sorts: string[]): this;
805
+ /**
806
+ * Navigate to the first page (page 1)
807
+ *
808
+ * @remarks Never throws. Idempotent when already on page 1.
809
+ * @returns {this}
810
+ */
811
+ firstPage(): this;
725
812
  /**
726
813
  * Generate a URI accordingly to the given data and active driver
727
814
  *
728
815
  * @returns {Observable<string>} An observable that emits the generated URI
729
816
  */
730
817
  generateUri(): Observable<string>;
818
+ /**
819
+ * Navigate directly to the specified page
820
+ *
821
+ * Validates integer/positive via the existing `setPage` path, and
822
+ * additionally rejects values that exceed `state.lastPage` when
823
+ * pagination bounds are known.
824
+ *
825
+ * @param n - Target page number
826
+ * @returns {this}
827
+ * @throws {InvalidPageNumberError} If `n` is not a positive integer, or if `n > state.lastPage` when `state.isLastPageKnown` is true
828
+ */
829
+ goToPage(n: number): this;
830
+ /**
831
+ * Check whether a next page exists
832
+ *
833
+ * @remarks Template-safe. Returns `true` when pagination bounds are unknown (conservative default — keeps a "Next" button enabled before the first `paginate()` call).
834
+ * @returns `true` if `state.page < state.lastPage` when bounds are known, or `true` when bounds are unknown
835
+ */
836
+ hasNextPage(): boolean;
837
+ /**
838
+ * Check whether a previous page exists
839
+ *
840
+ * @remarks Always safe. Does not require a synced paginated response.
841
+ * @returns `true` if `state.page > 1`
842
+ */
843
+ hasPreviousPage(): boolean;
844
+ /**
845
+ * Check whether the current page is the first page
846
+ *
847
+ * @remarks Always safe. Does not require a synced paginated response.
848
+ * @returns `true` if `state.page === 1`
849
+ */
850
+ isFirstPage(): boolean;
851
+ /**
852
+ * Check whether the current page is the last page
853
+ *
854
+ * @remarks Template-safe. Returns `false` when pagination bounds are unknown (no paginated response has been synced yet) — keeps "Next" navigation unblocked until the first `paginate()` call syncs.
855
+ * @returns `true` only when `state.isLastPageKnown` and `state.page === state.lastPage`
856
+ */
857
+ isLastPage(): boolean;
858
+ /**
859
+ * Navigate to the last page known from the most recent paginated response
860
+ *
861
+ * @remarks Requires at least one `PaginationService.paginate()` call to have synced `state.lastPage`. Before that, the bound is unknown and this method throws.
862
+ * @returns {this}
863
+ * @throws {PaginationNotSyncedError} If `state.isLastPageKnown` is false (no paginated response has been synced yet)
864
+ */
865
+ lastPage(): this;
866
+ /**
867
+ * Navigate to the next page
868
+ *
869
+ * @remarks Never throws. Idempotent at the known last page (no-op). Pair with `hasNextPage()` for a disable-state binding.
870
+ * @returns {this}
871
+ */
872
+ nextPage(): this;
873
+ /**
874
+ * Navigate to the previous page
875
+ *
876
+ * @remarks Never throws. Idempotent at page 1 (floored). Pair with `hasPreviousPage()` for a disable-state binding.
877
+ * @returns {this}
878
+ */
879
+ previousPage(): this;
731
880
  /**
732
881
  * Clear the current state and reset the Query Builder to a fresh, clean condition
733
882
  *
@@ -744,8 +893,14 @@ declare class NgQubeeService {
744
893
  /**
745
894
  * Set the items per page number
746
895
  *
747
- * @param limit - Number of items per page
896
+ * Validation is delegated to the active request strategy because the
897
+ * accepted range is driver-specific: nestjs-paginate additionally accepts
898
+ * `-1` as a "fetch all" sentinel, while Laravel, Spatie, and JSON:API
899
+ * require a positive integer.
900
+ *
901
+ * @param limit - Number of items per page (or `-1` to fetch all, NestJS only)
748
902
  * @returns {this}
903
+ * @throws {import('../errors/invalid-limit.error').InvalidLimitError} If the value is not accepted by the active driver
749
904
  */
750
905
  setLimit(limit: number): this;
751
906
  /**
@@ -772,7 +927,15 @@ declare class NgQubeeService {
772
927
  * @throws {UnsupportedSearchError} If the active driver does not support search
773
928
  */
774
929
  setSearch(search: string): this;
775
- static ɵfac: i0.ɵɵFactoryDeclaration<NgQubeeService, [null, null, null, { optional: true; }]>;
930
+ /**
931
+ * Get the total number of pages reported by the most recent paginated response
932
+ *
933
+ * @remarks Throws when called before any `paginate()` has synced a value. For a non-throwing read in a template, read `nest().isLastPageKnown` first as a guard.
934
+ * @returns The last page number
935
+ * @throws {PaginationNotSyncedError} If `state.isLastPageKnown` is false (no paginated response has been synced yet)
936
+ */
937
+ totalPages(): number;
938
+ static ɵfac: i0.ɵɵFactoryDeclaration<NgQubeeService, never>;
776
939
  static ɵprov: i0.ɵɵInjectableDeclaration<NgQubeeService>;
777
940
  }
778
941
 
@@ -824,6 +987,12 @@ interface IResponseStrategy {
824
987
  }
825
988
 
826
989
  declare class PaginationService {
990
+ /**
991
+ * The NestService instance that owns the query-builder state for this
992
+ * PaginationService's scope (environment-level by default, or
993
+ * component-level when used via `provideNgQubeeInstance()`)
994
+ */
995
+ private _nestService;
827
996
  /**
828
997
  * Resolved response key name options
829
998
  */
@@ -832,11 +1001,19 @@ declare class PaginationService {
832
1001
  * The response strategy that parses responses for the active driver
833
1002
  */
834
1003
  private _responseStrategy;
835
- constructor(responseStrategy: IResponseStrategy, options?: IPaginationConfig);
1004
+ constructor(nestService: NestService, responseStrategy: IResponseStrategy, options?: ResponseOptions);
836
1005
  /**
837
1006
  * Transform a raw API response into a typed PaginatedCollection
838
1007
  *
839
- * Delegates to the active driver's response strategy for parsing.
1008
+ * Delegates to the active driver's response strategy for parsing, then
1009
+ * auto-syncs the parsed `page` and `lastPage` back into `NestService`
1010
+ * so pagination navigation helpers on `NgQubeeService` can operate
1011
+ * against the live server-reported bounds without consumer bookkeeping.
1012
+ *
1013
+ * @remarks
1014
+ * `lastPage` is only synced when the response yields a positive integer.
1015
+ * Server-emitted `0` (empty collection edge case) and absent fields are
1016
+ * treated as "no useful info" and leave `isLastPageKnown: false`.
840
1017
  *
841
1018
  * @param response - The raw API response object
842
1019
  * @returns A typed PaginatedCollection instance
@@ -844,12 +1021,24 @@ declare class PaginationService {
844
1021
  paginate<T extends IPaginatedObject>(response: {
845
1022
  [key: string]: any;
846
1023
  }): PaginatedCollection<T>;
847
- static ɵfac: i0.ɵɵFactoryDeclaration<PaginationService, [null, { optional: true; }]>;
1024
+ static ɵfac: i0.ɵɵFactoryDeclaration<PaginationService, never>;
848
1025
  static ɵprov: i0.ɵɵInjectableDeclaration<PaginationService>;
849
1026
  }
850
1027
 
1028
+ /**
1029
+ * Thrown when a limit value does not satisfy the active driver's constraints
1030
+ *
1031
+ * Validation is driver-scoped: most drivers require an integer `>= 1`, while
1032
+ * the NestJS driver additionally accepts `-1` as a "fetch all items" sentinel
1033
+ * (as documented by nestjs-paginate). The message is tailored accordingly so
1034
+ * the caller understands which values are permitted.
1035
+ */
851
1036
  declare class InvalidLimitError extends Error {
852
- constructor(limit: number);
1037
+ /**
1038
+ * @param limit - The rejected limit value
1039
+ * @param allowFetchAll - Whether the active driver accepts `-1` (fetch all)
1040
+ */
1041
+ constructor(limit: number, allowFetchAll?: boolean);
853
1042
  }
854
1043
 
855
1044
  declare class InvalidPageNumberError extends Error {
@@ -869,6 +1058,24 @@ declare class KeyNotFoundError extends Error {
869
1058
  constructor(key: string);
870
1059
  }
871
1060
 
1061
+ /**
1062
+ * Thrown when a pagination helper that needs `state.lastPage` is called
1063
+ * before `PaginationService.paginate()` has ever synced a value.
1064
+ *
1065
+ * Examples: `NgQubeeService.lastPage()`, `NgQubeeService.totalPages()`.
1066
+ *
1067
+ * Safe-for-templates predicates (`isLastPage`, `hasNextPage`, etc.) do not
1068
+ * throw and return conservative defaults instead.
1069
+ */
1070
+ declare class PaginationNotSyncedError extends Error {
1071
+ /**
1072
+ * @param action - Short imperative describing what the caller was trying
1073
+ * to do (e.g. "navigate to last page", "read totalPages"). Surfaced in
1074
+ * the error message so the cause is obvious at the call site.
1075
+ */
1076
+ constructor(action: string);
1077
+ }
1078
+
872
1079
  declare class UnselectableModelError extends Error {
873
1080
  constructor(model: string);
874
1081
  }
@@ -946,6 +1153,227 @@ interface INestState {
946
1153
  interface IPage {
947
1154
  }
948
1155
 
1156
+ /**
1157
+ * Injection token for the active pagination driver
1158
+ *
1159
+ * Provided by `provideNgQubee()` / `NgQubeeModule.forRoot()` from the
1160
+ * user-supplied `IConfig.driver`. Services read it to gate driver-specific
1161
+ * behavior (e.g. `NgQubeeService._assertDriver`).
1162
+ */
1163
+ declare const NG_QUBEE_DRIVER: InjectionToken<DriverEnum>;
1164
+ /**
1165
+ * Injection token for the resolved request URI strategy
1166
+ *
1167
+ * Provided by `provideNgQubee()` / `NgQubeeModule.forRoot()` based on the
1168
+ * active driver. Used by `NgQubeeService` to build request URIs.
1169
+ */
1170
+ declare const NG_QUBEE_REQUEST_STRATEGY: InjectionToken<IRequestStrategy>;
1171
+ /**
1172
+ * Injection token for the resolved request query-parameter key options
1173
+ *
1174
+ * Provided as a fully-built `QueryBuilderOptions` instance. `provideNgQubee()`
1175
+ * constructs it from `IConfig.request`; consumers don't interact with this
1176
+ * token directly.
1177
+ */
1178
+ declare const NG_QUBEE_REQUEST_OPTIONS: InjectionToken<QueryBuilderOptions>;
1179
+ /**
1180
+ * Injection token for the resolved response parsing strategy
1181
+ *
1182
+ * Provided by `provideNgQubee()` / `NgQubeeModule.forRoot()` based on the
1183
+ * active driver. Used by `PaginationService` to parse paginated responses.
1184
+ */
1185
+ declare const NG_QUBEE_RESPONSE_STRATEGY: InjectionToken<IResponseStrategy>;
1186
+ /**
1187
+ * Injection token for the resolved response field-key options
1188
+ *
1189
+ * Provided as a fully-built `ResponseOptions` instance (or a driver-specific
1190
+ * subclass like `JsonApiResponseOptions` / `NestjsResponseOptions`).
1191
+ * `provideNgQubee()` constructs the correct variant from `IConfig.response`.
1192
+ */
1193
+ declare const NG_QUBEE_RESPONSE_OPTIONS: InjectionToken<ResponseOptions>;
1194
+
1195
+ /**
1196
+ * Request strategy for the JSON:API driver
1197
+ *
1198
+ * Generates URIs in the JSON:API format:
1199
+ * - Fields: `fields[articles]=title,body&fields[people]=name`
1200
+ * - Filters: `filter[status]=active`
1201
+ * - Includes: `include=author,comments.author`
1202
+ * - Pagination: `page[number]=1&page[size]=15`
1203
+ * - Sort: `sort=-created_at,name` (- prefix = DESC)
1204
+ *
1205
+ * @see https://jsonapi.org/format/
1206
+ */
1207
+ declare class JsonApiRequestStrategy implements IRequestStrategy {
1208
+ /**
1209
+ * Accumulator for composing the URI string
1210
+ */
1211
+ private _uri;
1212
+ /**
1213
+ * Build a URI string from the given state using the JSON:API format
1214
+ *
1215
+ * @param state - The current query builder state
1216
+ * @param options - The query parameter key name configuration
1217
+ * @returns The composed URI string
1218
+ * @throws Error if resource is not set
1219
+ */
1220
+ buildUri(state: IQueryBuilderState, options: QueryBuilderOptions): string;
1221
+ /**
1222
+ * Validate that the given limit is accepted by the JSON:API driver
1223
+ *
1224
+ * The JSON:API specification leaves pagination semantics to the server and
1225
+ * does not define a "fetch all" sentinel, so only positive integers are
1226
+ * accepted.
1227
+ *
1228
+ * @param limit - The limit value to validate
1229
+ * @throws {InvalidLimitError} If the value is not a positive integer
1230
+ */
1231
+ validateLimit(limit: number): void;
1232
+ /**
1233
+ * Parse and append field selection parameters
1234
+ *
1235
+ * Validates that each field model exists either as the main resource
1236
+ * or in the includes list. Fields are grouped by type in bracket notation.
1237
+ *
1238
+ * @param state - The current query builder state
1239
+ * @param options - The query parameter key name configuration
1240
+ * @returns The generated field selection parameter string
1241
+ * @throws Error if resource is required but not set
1242
+ * @throws UnselectableModelError if a field model is not in resource or includes
1243
+ */
1244
+ private _parseFields;
1245
+ /**
1246
+ * Parse and append filter parameters
1247
+ *
1248
+ * Generates filter parameters in bracket notation: `filter[key]=value1,value2`
1249
+ *
1250
+ * @param state - The current query builder state
1251
+ * @param options - The query parameter key name configuration
1252
+ * @returns The generated filter parameter string
1253
+ */
1254
+ private _parseFilters;
1255
+ /**
1256
+ * Parse and append include parameters
1257
+ *
1258
+ * Generates: `include=author,comments.author`
1259
+ *
1260
+ * @param state - The current query builder state
1261
+ * @param options - The query parameter key name configuration
1262
+ * @returns The generated include parameter string
1263
+ */
1264
+ private _parseIncludes;
1265
+ /**
1266
+ * Parse and append pagination parameters in JSON:API bracket notation
1267
+ *
1268
+ * Generates: `page[number]=1&page[size]=15`
1269
+ *
1270
+ * @param state - The current query builder state
1271
+ * @param options - The query parameter key name configuration
1272
+ * @returns The generated pagination parameter string
1273
+ */
1274
+ private _parsePagination;
1275
+ /**
1276
+ * Parse and append sort parameters
1277
+ *
1278
+ * Generates: `sort=-field1,field2` where `-` prefix indicates DESC order
1279
+ *
1280
+ * @param state - The current query builder state
1281
+ * @param options - The query parameter key name configuration
1282
+ * @returns The generated sort parameter string
1283
+ */
1284
+ private _parseSort;
1285
+ /**
1286
+ * Determine the appropriate URI prefix based on the current accumulator state
1287
+ *
1288
+ * Returns the full base path with `?` for the first parameter,
1289
+ * or `&` for subsequent parameters.
1290
+ *
1291
+ * @param state - The current query builder state
1292
+ * @returns The prefix string to prepend to the next parameter
1293
+ */
1294
+ private _prepend;
1295
+ }
1296
+
1297
+ /**
1298
+ * Response strategy for the JSON:API driver
1299
+ *
1300
+ * Parses JSON:API pagination responses:
1301
+ * ```json
1302
+ * {
1303
+ * "data": [...],
1304
+ * "meta": {
1305
+ * "current-page": 1,
1306
+ * "per-page": 10,
1307
+ * "total": 100,
1308
+ * "page-count": 10,
1309
+ * "from": 1,
1310
+ * "to": 10
1311
+ * },
1312
+ * "links": {
1313
+ * "first": "url",
1314
+ * "prev": "url",
1315
+ * "next": "url",
1316
+ * "last": "url"
1317
+ * }
1318
+ * }
1319
+ * ```
1320
+ *
1321
+ * @see https://jsonapi.org/format/
1322
+ */
1323
+ declare class JsonApiResponseStrategy implements IResponseStrategy {
1324
+ /**
1325
+ * Parse a JSON:API pagination response into a PaginatedCollection
1326
+ *
1327
+ * Supports dot-notation key paths for accessing nested values.
1328
+ * Computes `from` and `to` from `currentPage` and `perPage` when
1329
+ * they are not directly available in the response.
1330
+ *
1331
+ * @param response - The raw API response object
1332
+ * @param options - The response key name configuration
1333
+ * @returns A typed PaginatedCollection instance
1334
+ */
1335
+ paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
1336
+ /**
1337
+ * Resolve a value from a response object using a dot-notation path
1338
+ *
1339
+ * Supports both flat keys ('data') and nested paths ('meta.current-page').
1340
+ *
1341
+ * @param response - The raw response object
1342
+ * @param path - The dot-notation path to resolve
1343
+ * @returns The resolved value, or undefined if not found
1344
+ */
1345
+ private _resolve;
1346
+ /**
1347
+ * Resolve the "from" index value
1348
+ *
1349
+ * If the path resolves to a value in the response, use it.
1350
+ * Otherwise, compute it from currentPage and perPage:
1351
+ * `(currentPage - 1) * perPage + 1`
1352
+ *
1353
+ * @param response - The raw response object
1354
+ * @param options - The response key name configuration
1355
+ * @param currentPage - The current page number
1356
+ * @param perPage - The number of items per page
1357
+ * @returns The computed "from" index
1358
+ */
1359
+ private _resolveFrom;
1360
+ /**
1361
+ * Resolve the "to" index value
1362
+ *
1363
+ * If the path resolves to a value in the response, use it.
1364
+ * Otherwise, compute it from currentPage, perPage, and total:
1365
+ * `Math.min(currentPage * perPage, total)`
1366
+ *
1367
+ * @param response - The raw response object
1368
+ * @param options - The response key name configuration
1369
+ * @param currentPage - The current page number
1370
+ * @param perPage - The number of items per page
1371
+ * @param total - The total number of items
1372
+ * @returns The computed "to" index
1373
+ */
1374
+ private _resolveTo;
1375
+ }
1376
+
949
1377
  /**
950
1378
  * Request strategy for the Laravel (pagination-only) driver
951
1379
  *
@@ -964,6 +1392,16 @@ declare class LaravelRequestStrategy implements IRequestStrategy {
964
1392
  * @throws Error if resource is not set
965
1393
  */
966
1394
  buildUri(state: IQueryBuilderState, options: QueryBuilderOptions): string;
1395
+ /**
1396
+ * Validate that the given limit is accepted by the Laravel driver
1397
+ *
1398
+ * Laravel pagination does not recognize `-1` as a "fetch all" sentinel,
1399
+ * so only positive integers are accepted.
1400
+ *
1401
+ * @param limit - The limit value to validate
1402
+ * @throws {InvalidLimitError} If the value is not a positive integer
1403
+ */
1404
+ validateLimit(limit: number): void;
967
1405
  }
968
1406
 
969
1407
  /**
@@ -1020,6 +1458,16 @@ declare class NestjsRequestStrategy implements IRequestStrategy {
1020
1458
  * @throws Error if model is not set
1021
1459
  */
1022
1460
  buildUri(state: IQueryBuilderState, options: QueryBuilderOptions): string;
1461
+ /**
1462
+ * Validate that the given limit is accepted by nestjs-paginate
1463
+ *
1464
+ * Accepts any integer `>= 1` as a page size, plus `-1` which nestjs-paginate
1465
+ * interprets as "fetch all items" (server must opt-in via `maxLimit: -1`).
1466
+ *
1467
+ * @param limit - The limit value to validate
1468
+ * @throws {InvalidLimitError} If the value is not an integer, or is 0, or is a negative number other than -1
1469
+ */
1470
+ validateLimit(limit: number): void;
1023
1471
  /**
1024
1472
  * Parse and append simple filter parameters
1025
1473
  *
@@ -1198,6 +1646,16 @@ declare class SpatieRequestStrategy implements IRequestStrategy {
1198
1646
  * @throws Error if resource is not set
1199
1647
  */
1200
1648
  buildUri(state: IQueryBuilderState, options: QueryBuilderOptions): string;
1649
+ /**
1650
+ * Validate that the given limit is accepted by the Spatie driver
1651
+ *
1652
+ * Spatie query-builder does not recognize `-1` as a "fetch all" sentinel,
1653
+ * so only positive integers are accepted.
1654
+ *
1655
+ * @param limit - The limit value to validate
1656
+ * @throws {InvalidLimitError} If the value is not a positive integer
1657
+ */
1658
+ validateLimit(limit: number): void;
1201
1659
  /**
1202
1660
  * Parse and append field selection parameters
1203
1661
  *
@@ -1298,5 +1756,5 @@ declare class SpatieResponseStrategy implements IResponseStrategy {
1298
1756
  paginate<T extends IPaginatedObject>(response: Record<string, any>, options: ResponseOptions): PaginatedCollection<T>;
1299
1757
  }
1300
1758
 
1301
- export { DriverEnum, FilterOperatorEnum, InvalidLimitError, InvalidPageNumberError, InvalidResourceNameError, KeyNotFoundError, LaravelRequestStrategy, LaravelResponseStrategy, NestjsRequestStrategy, NestjsResponseStrategy, NgQubeeModule, NgQubeeService, PaginatedCollection, PaginationService, SortEnum, SpatieRequestStrategy, SpatieResponseStrategy, UnselectableModelError, UnsupportedFieldSelectionError, UnsupportedFilterError, UnsupportedFilterOperatorError, UnsupportedIncludesError, UnsupportedSearchError, UnsupportedSelectError, UnsupportedSortError, provideNgQubee };
1759
+ export { DriverEnum, FilterOperatorEnum, 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, PaginationNotSyncedError, PaginationService, SortEnum, SpatieRequestStrategy, SpatieResponseStrategy, UnselectableModelError, UnsupportedFieldSelectionError, UnsupportedFilterError, UnsupportedFilterOperatorError, UnsupportedIncludesError, UnsupportedSearchError, UnsupportedSelectError, UnsupportedSortError, buildNgQubeeProviders, provideNgQubee, provideNgQubeeInstance };
1302
1760
  export type { IConfig, IFields, IFilters, INestState, IOperatorFilter, IPage, IPaginatedObject, IPaginationConfig, IQueryBuilderConfig, IQueryBuilderState, IRequestStrategy, IResponseStrategy, ISort };