@reforgium/statum 2.1.1 → 2.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.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @reforgium/statum
1
+ # @reforgium/statum
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/%40reforgium%2Fstatum.svg)](https://www.npmjs.com/package/@reforgium/statum)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -181,7 +181,7 @@ entities.removeOne(1);
181
181
 
182
182
  ## PaginatedDataStore
183
183
 
184
- Lightweight store for server-side pagination with sorting, filtering, and page cache.
184
+ Lightweight store for server-side pagination, filtering, and page cache.
185
185
 
186
186
  ### When to use
187
187
 
@@ -201,23 +201,22 @@ Lightweight store for server-side pagination with sorting, filtering, and page c
201
201
  | pageSize | `number` | Page size |
202
202
  | totalElements | `number` | Total items on server |
203
203
  | filters | `Partial<F>` | Active filters |
204
- | sort | `string \| undefined` | Sort as `"field,asc"` / `"field,desc"` |
205
204
 
206
205
  ### Methods
207
206
 
208
- | Method | Description |
209
- |----------------|---------------------------------------------------|
210
- | refresh | Repeat request with current params |
211
- | updatePage | Change page (can use cache) |
212
- | updatePageSize | Change page size (can use cache) |
213
- | updateFilters | Merge filters, reset cache, go to page 0 |
214
- | setFilters | Replace filters, reset cache + sort, go to page 0 |
215
- | updateQuery | Map table events to `page`/`sort` |
216
- | updateRoute | Change endpoint, reset meta/cache |
217
- | setRouteParams | Fill route url with params |
218
- | updateConfig | Patch config and apply presets |
219
- | copy | Copy config/meta from another store |
220
- | destroy | Manual destroying of caches and abort requests |
207
+ | Method | Description |
208
+ |----------------|------------------------------------------------|
209
+ | refresh | Repeat request with current params |
210
+ | updatePage | Change page (can use cache) |
211
+ | updatePageSize | Change page size (can use cache) |
212
+ | updateFilters | Merge filters, reset cache, go to page 0 |
213
+ | setFilters | Replace filters, reset cache, go to page 0 |
214
+ | updateQuery | Map table events to `page` |
215
+ | updateRoute | Change endpoint, reset meta/cache |
216
+ | setRouteParams | Fill route url with params |
217
+ | updateConfig | Patch config and apply presets |
218
+ | copy | Copy config/meta from another store |
219
+ | destroy | Manual destroying of caches and abort requests |
221
220
 
222
221
  Example:
223
222
 
@@ -1013,7 +1013,14 @@ class ResourceStore {
1013
1013
  abort(method, args, reason) {
1014
1014
  const url = this.buildUrl(method, args);
1015
1015
  const key = buildKey(method, url, args);
1016
+ const entry = this.entries.get(key);
1016
1017
  this.trace({ type: 'abort', method, key });
1018
+ if (entry) {
1019
+ entry.inflight = undefined;
1020
+ if (entry.status === 'loading' || entry.status === 'stale') {
1021
+ entry.status = 'idle';
1022
+ }
1023
+ }
1017
1024
  this.scheduler.cancel?.(key, reason);
1018
1025
  }
1019
1026
  /**
@@ -1023,6 +1030,12 @@ class ResourceStore {
1023
1030
  */
1024
1031
  abortAll(reason) {
1025
1032
  this.trace({ type: 'abort', method: 'GET', key: '*' });
1033
+ this.entries.forEach((entry) => {
1034
+ entry.inflight = undefined;
1035
+ if (entry.status === 'loading' || entry.status === 'stale') {
1036
+ entry.status = 'idle';
1037
+ }
1038
+ });
1026
1039
  this.scheduler.cancelAll?.(reason);
1027
1040
  }
1028
1041
  ensureEntry(key) {
@@ -1212,7 +1225,7 @@ class ResourceStore {
1212
1225
  *
1213
1226
  * Provides:
1214
1227
  * - reactive signals: `items`, `loading`, `cached`;
1215
- * - methods to control page/size/filters/sorting;
1228
+ * - methods to control page/size/filters;
1216
1229
  * - optional LRU cache by pages;
1217
1230
  * - configurable transport (GET/POST/PATCH/…).
1218
1231
  *
@@ -1237,8 +1250,6 @@ class PaginatedDataStore {
1237
1250
  loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1238
1251
  /** Current filters (applied to requests). */
1239
1252
  filters = {};
1240
- /** Current sorting (`field,asc|desc`). */
1241
- sort;
1242
1253
  /** Current page index (0-based). */
1243
1254
  page = 0;
1244
1255
  /** Default page size. */
@@ -1259,7 +1270,7 @@ class PaginatedDataStore {
1259
1270
  this.initTransport();
1260
1271
  inject(DestroyRef).onDestroy(() => this.destroy());
1261
1272
  }
1262
- /** Force reload current data (with the same page/filters/sort). */
1273
+ /** Force reload current data (with the same page/filters). */
1263
1274
  refresh() {
1264
1275
  return this.#fetchItems({});
1265
1276
  }
@@ -1298,21 +1309,20 @@ class PaginatedDataStore {
1298
1309
  };
1299
1310
  /**
1300
1311
  * Update the state from table events (PrimeNG, etc.) and fetch.
1301
- * Supports `page/first/rows/sortField/sortOrder`.
1312
+ * Supports `page/first/rows`.
1302
1313
  */
1303
- updateQuery = ({ page: pageNum, first = 0, rows = 0, sortOrder, sortField }) => {
1314
+ updateQuery = ({ page: pageNum, first = 0, rows = 0 }) => {
1304
1315
  const page = (pageNum ?? (first && rows && Math.floor(first / rows))) || 0;
1305
- const sort = sortField ? `${sortField},${sortOrder === 1 ? 'asc' : 'desc'}` : '';
1306
- return this.#fetchItems({ page, sort });
1316
+ return this.#fetchItems({ page });
1307
1317
  };
1308
1318
  /**
1309
- * Set filters from scratch (goes to the first page and resets sorting) and fetch.
1319
+ * Set filters from scratch (goes to the first page) and fetch.
1310
1320
  * Useful for quick presets.
1311
1321
  */
1312
1322
  setFilters = (filters = {}) => {
1313
1323
  this.#cache.clear();
1314
1324
  this.cached.set([]);
1315
- return this.#fetchItems({ page: 0, filters, sort: undefined });
1325
+ return this.#fetchItems({ page: 0, filters });
1316
1326
  };
1317
1327
  /**
1318
1328
  * Change the resource route (resets page, cache, and presets) without fetching.
@@ -1394,14 +1404,13 @@ class PaginatedDataStore {
1394
1404
  }
1395
1405
  }
1396
1406
  }
1397
- #fetchItems = async ({ page = this.page, size = this.pageSize, sort = this.sort, filters = this.filters, }) => {
1398
- const query = this.parseQuery({ page, size, sort, filters });
1407
+ #fetchItems = async ({ page = this.page, size = this.pageSize, filters = this.filters }) => {
1408
+ const query = this.parseQuery({ page, size, filters });
1399
1409
  this.loading.set(true);
1400
1410
  this.#transport.abortAll();
1401
1411
  try {
1402
1412
  const response = await this.runTransport(filters, query);
1403
1413
  this.page = page;
1404
- this.sort = sort;
1405
1414
  this.filters = filters;
1406
1415
  const parsed = await this.parseResponseData(response);
1407
1416
  this.pageSize = parsed.pageable?.pageSize || size;
@@ -1424,7 +1433,7 @@ class PaginatedDataStore {
1424
1433
  this.#transport = new ResourceStore({ [this.config.method || 'GET']: this.route }, {
1425
1434
  delay: this.config.debounceTime,
1426
1435
  delayMode: 'debounce',
1427
- presetQueries: { page: this.page, size: this.pageSize, sort: this.sort },
1436
+ presetQueries: { page: this.page, size: this.pageSize },
1428
1437
  presetPayload: this.filters,
1429
1438
  });
1430
1439
  }
@@ -1437,10 +1446,10 @@ class PaginatedDataStore {
1437
1446
  // @ts-ignore
1438
1447
  return this.#transport[method]({ query, payload, params }, { promote: false, dedupe: true });
1439
1448
  }
1440
- parseQuery({ page = 0, size, sort, filters }) {
1449
+ parseQuery({ page = 0, size, filters }) {
1441
1450
  const method = this.config.method || 'GET';
1442
1451
  const requestPayload = { page, size, ...(method === 'GET' ? filters : {}) };
1443
- const rawQueries = this.config.parseRequest?.({ ...requestPayload, sort }) || requestPayload;
1452
+ const rawQueries = this.config.parseRequest?.({ ...requestPayload }) || requestPayload;
1444
1453
  const queries = {};
1445
1454
  Object.entries(rawQueries).forEach(([key, value]) => {
1446
1455
  if (Array.isArray(value)) {
@@ -1450,7 +1459,6 @@ class PaginatedDataStore {
1450
1459
  queries[key] = value;
1451
1460
  }
1452
1461
  });
1453
- sort && (queries['sort'] = sort);
1454
1462
  return queries;
1455
1463
  }
1456
1464
  parseResponseData = async (data) => {
@@ -1496,7 +1504,6 @@ class PaginatedDataStore {
1496
1504
  this.filters = this.config.presetFilters || {};
1497
1505
  this.pageSize = this.config.presetQuery?.pageSize || 20;
1498
1506
  this.page = this.config.presetQuery?.page || 0;
1499
- this.sort = this.config.presetQuery?.sort;
1500
1507
  }
1501
1508
  }
1502
1509
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.1.1",
2
+ "version": "2.2.0",
3
3
  "name": "@reforgium/statum",
4
4
  "description": "reforgium State modules",
5
5
  "author": "rtommievich",
@@ -585,17 +585,16 @@ type PaginatedDataStoreConfig<ItemsType extends object, FilterType = unknown> =
585
585
  cacheSize?: number;
586
586
  /** Debounce delay before request (ms). Useful for frequent filter changes. */
587
587
  debounceTime?: number;
588
- /** Initial pagination/sort params. `page` is required. */
588
+ /** Initial pagination params. `page` is required. */
589
589
  presetQuery?: {
590
590
  page: number;
591
591
  pageSize?: number;
592
- sort?: string;
593
592
  };
594
593
  /** Initial filters. Will be sent with the first request. */
595
594
  presetFilters?: Partial<FilterType>;
596
595
  /**
597
596
  * Custom transformation of request data into a query object.
598
- * Useful for mapping `page/pageSize/sort` → API-specific keys.
597
+ * Useful for mapping `page/pageSize` → API-specific keys.
599
598
  */
600
599
  parseRequest?: (data: PageableRequest) => Query;
601
600
  /**
@@ -611,9 +610,9 @@ type PaginatedDataStoreConfig<ItemsType extends object, FilterType = unknown> =
611
610
  type PaginatedDataStoreProviderConfig = {
612
611
  /** Default method for all stores (if not overridden locally). */
613
612
  defaultMethod?: RestMethods;
614
- /** Default base `page/pageSize/sort`. */
613
+ /** Default base `page/pageSize`. */
615
614
  defaultQuery?: PaginatedDataStoreConfig<object>['presetQuery'];
616
- /** Global `parseRequest` — maps pagination/sort into a query object. */
615
+ /** Global `parseRequest` — maps pagination into a query object. */
617
616
  defaultParseRequest?: PaginatedDataStoreConfig<object>['parseRequest'];
618
617
  /** Whether to enable page cache by default. */
619
618
  defaultHasCache?: boolean;
@@ -625,15 +624,13 @@ type PaginationType = {
625
624
  page?: number;
626
625
  first?: number | null;
627
626
  rows?: number | null;
628
- sortField?: string | string[] | null;
629
- sortOrder?: number | null;
630
627
  };
631
628
  /**
632
629
  * Store for paginated data (tables/lists) with per-page cache and unified requests.
633
630
  *
634
631
  * Provides:
635
632
  * - reactive signals: `items`, `loading`, `cached`;
636
- * - methods to control page/size/filters/sorting;
633
+ * - methods to control page/size/filters;
637
634
  * - optional LRU cache by pages;
638
635
  * - configurable transport (GET/POST/PATCH/…).
639
636
  *
@@ -657,8 +654,6 @@ declare class PaginatedDataStore<ItemsType extends object, FilterType = unknown>
657
654
  loading: WritableSignal<boolean>;
658
655
  /** Current filters (applied to requests). */
659
656
  filters: Partial<FilterType>;
660
- /** Current sorting (`field,asc|desc`). */
661
- sort?: string | ReadonlyArray<string>;
662
657
  /** Current page index (0-based). */
663
658
  page: number;
664
659
  /** Default page size. */
@@ -671,7 +666,7 @@ declare class PaginatedDataStore<ItemsType extends object, FilterType = unknown>
671
666
  * @param config Store behavior: method, cache, request/response parsers, debounce, presets, etc.
672
667
  */
673
668
  constructor(route: string, config?: PaginatedDataStoreConfig<ItemsType, FilterType>);
674
- /** Force reload current data (with the same page/filters/sort). */
669
+ /** Force reload current data (with the same page/filters). */
675
670
  refresh(): Promise<ItemsType[] | undefined>;
676
671
  /**
677
672
  * Switch page with a request.
@@ -692,11 +687,11 @@ declare class PaginatedDataStore<ItemsType extends object, FilterType = unknown>
692
687
  updateFilters: (filters: Partial<FilterType>) => Promise<ItemsType[] | undefined>;
693
688
  /**
694
689
  * Update the state from table events (PrimeNG, etc.) and fetch.
695
- * Supports `page/first/rows/sortField/sortOrder`.
690
+ * Supports `page/first/rows`.
696
691
  */
697
- updateQuery: ({ page: pageNum, first, rows, sortOrder, sortField }: PaginationType) => Promise<ItemsType[] | undefined>;
692
+ updateQuery: ({ page: pageNum, first, rows }: PaginationType) => Promise<ItemsType[] | undefined>;
698
693
  /**
699
- * Set filters from scratch (goes to the first page and resets sorting) and fetch.
694
+ * Set filters from scratch (goes to the first page) and fetch.
700
695
  * Useful for quick presets.
701
696
  */
702
697
  setFilters: (filters?: Partial<FilterType>) => Promise<ItemsType[] | undefined>;
@@ -779,7 +774,7 @@ type DictStoreConfig<ItemsType extends object> = {
779
774
  /** Autoload data on initialization (`true` by default). */
780
775
  autoLoad?: boolean | 'whenEmpty';
781
776
  /**
782
- * Custom mapper of pagination/sort request into query params.
777
+ * Custom mapper of pagination request into query params.
783
778
  * Useful if the API expects non-standard field names.
784
779
  */
785
780
  parseRequest?: (data: PageableRequest) => AnyDict;