live-cache 0.2.0 → 0.2.2

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.
@@ -46,19 +46,20 @@ export interface ControllerOptions<TVariable, TName extends string> {
46
46
  storageManager?: StorageManager<TVariable[]>;
47
47
  pageSize?: number;
48
48
  invalidator?: Invalidator<TVariable>;
49
- initialiseOnMount?: boolean;
50
49
  }
51
50
  export default class Controller<TVariable, TName extends string> {
52
51
  name: TName;
53
52
  collection: Collection<TVariable, TName>;
54
53
  protected subscribers: Set<(model: ModelType<TVariable>[]) => void>;
55
- protected storageManager: StorageManager<TVariable[]>;
54
+ storageManager: StorageManager<TVariable[]>;
56
55
  loading: boolean;
57
56
  error: unknown;
58
57
  total: number;
59
- pageSize: number;
58
+ page: number;
59
+ limit: number;
60
60
  abortController: AbortController | null;
61
61
  invalidator: Invalidator<TVariable>;
62
+ initialised: boolean;
62
63
  /**
63
64
  * Abort any in-flight work owned by this controller (typically network fetches).
64
65
  *
@@ -66,15 +67,18 @@ export default class Controller<TVariable, TName extends string> {
66
67
  * pass `this.abortController.signal` to the next request.
67
68
  */
68
69
  abort(): void;
69
- protected updateTotal(total: number): void;
70
- protected updatePageSize(pageSize: number): void;
70
+ updateTotal(total: number): void;
71
+ updatePage(page: number): void;
72
+ updateLimit(limit: number): void;
71
73
  /**
72
74
  * Fetch the complete dataset for this controller.
73
75
  *
74
76
  * Subclasses must implement this. Return `[rows, total]` where `total` is the
75
77
  * total number of rows available on the backend (useful for pagination).
76
78
  */
77
- fetchAll(): Promise<[TVariable[], number]>;
79
+ fetch(where?: string | Partial<TVariable>): Promise<[TVariable[], number]>;
80
+ nextPage(where?: string | Partial<TVariable>): Promise<void>;
81
+ previousPage(where?: string | Partial<TVariable>): Promise<void>;
78
82
  /**
79
83
  * Initialise (hydrate) the controller's collection.
80
84
  *
@@ -85,7 +89,7 @@ export default class Controller<TVariable, TName extends string> {
85
89
  *
86
90
  * A successful initialise ends with `commit()` so subscribers receive the latest snapshot.
87
91
  */
88
- initialise(): Promise<void>;
92
+ initialise(where?: string | Partial<TVariable>): Promise<void>;
89
93
  /**
90
94
  * Subscribe to controller updates.
91
95
  *
@@ -99,13 +103,13 @@ export default class Controller<TVariable, TName extends string> {
99
103
  * unsubscribe();
100
104
  * ```
101
105
  */
102
- publish(onChange: (data: ModelType<TVariable>[]) => void): () => boolean;
106
+ subscribe(onChange: (models: ModelType<TVariable>[]) => void): () => boolean;
103
107
  /**
104
108
  * Persist the latest snapshot and notify all subscribers.
105
109
  *
106
110
  * This is intentionally private: consumers should use `commit()` which computes the snapshot.
107
111
  */
108
- private subscribe;
112
+ private publish;
109
113
  /**
110
114
  * Publish + persist the current snapshot.
111
115
  *
@@ -119,7 +123,7 @@ export default class Controller<TVariable, TName extends string> {
119
123
  *
120
124
  * Subclasses typically use this inside `invalidate()`.
121
125
  */
122
- protected refetch(): Promise<void>;
126
+ update(where?: string | Partial<TVariable>): Promise<void>;
123
127
  /**
124
128
  * Invalidate the cache for this controller.
125
129
  *
@@ -144,5 +148,5 @@ export default class Controller<TVariable, TName extends string> {
144
148
  * @param storageManager - where snapshots are persisted (defaults to no-op)
145
149
  * @param pageSize - optional pagination hint (userland)
146
150
  */
147
- constructor(name: TName, { storageManager, pageSize, invalidator, initialiseOnMount, }: ControllerOptions<TVariable, TName>);
151
+ constructor(name: TName, { storageManager, pageSize, invalidator, }: ControllerOptions<TVariable, TName>);
148
152
  }
@@ -38,7 +38,7 @@ export default class ObjectStore {
38
38
  /**
39
39
  * Initialise a controller once per store, even if multiple callers request it.
40
40
  */
41
- initialiseOnce<TVariable, TName extends string>(name: TName): Promise<void>;
41
+ initialiseOnce<TVariable, TName extends string>(name: TName, where?: string | Partial<TVariable>): Promise<void>;
42
42
  }
43
43
  /**
44
44
  * Returns a singleton store instance.
package/dist/index.cjs CHANGED
@@ -529,14 +529,17 @@ class Controller {
529
529
  abort() {
530
530
  if (this.abortController) {
531
531
  this.abortController.abort();
532
+ this.abortController = null;
532
533
  }
533
- this.abortController = new AbortController();
534
534
  }
535
535
  updateTotal(total) {
536
536
  this.total = total;
537
537
  }
538
- updatePageSize(pageSize) {
539
- this.pageSize = pageSize;
538
+ updatePage(page) {
539
+ this.page = page;
540
+ }
541
+ updateLimit(limit) {
542
+ this.limit = limit;
540
543
  }
541
544
  /**
542
545
  * Fetch the complete dataset for this controller.
@@ -544,11 +547,23 @@ class Controller {
544
547
  * Subclasses must implement this. Return `[rows, total]` where `total` is the
545
548
  * total number of rows available on the backend (useful for pagination).
546
549
  */
547
- fetchAll() {
550
+ fetch(where) {
548
551
  return __awaiter(this, void 0, void 0, function* () {
549
552
  throw Error("Not Implemented");
550
553
  });
551
554
  }
555
+ nextPage(where) {
556
+ return __awaiter(this, void 0, void 0, function* () {
557
+ this.updatePage(this.page + 1);
558
+ yield this.update(where);
559
+ });
560
+ }
561
+ previousPage(where) {
562
+ return __awaiter(this, void 0, void 0, function* () {
563
+ this.updatePage(this.page - 1);
564
+ yield this.update(where);
565
+ });
566
+ }
552
567
  /**
553
568
  * Initialise (hydrate) the controller's collection.
554
569
  *
@@ -559,37 +574,41 @@ class Controller {
559
574
  *
560
575
  * A successful initialise ends with `commit()` so subscribers receive the latest snapshot.
561
576
  */
562
- initialise() {
577
+ initialise(where) {
563
578
  return __awaiter(this, void 0, void 0, function* () {
564
- var _a;
565
- if (this.loading)
566
- return;
579
+ this.abortController = new AbortController();
567
580
  // If the collection is not empty, return.
568
- let data = this.collection.find().map((doc) => doc.toData());
581
+ let data = this.collection.find(where).map((doc) => doc.toData());
569
582
  if (data.length !== 0) {
570
- return;
571
- }
572
- // If the collection is empty, check the storage manager.
573
- data = (_a = (yield this.storageManager.get(this.name))) !== null && _a !== void 0 ? _a : [];
574
- if (data.length !== 0) {
575
- this.updateTotal(this.collection.find().length);
576
- this.collection.insertMany(data);
583
+ this.updateTotal(data.length);
577
584
  yield this.commit();
578
585
  return;
579
586
  }
587
+ const fromStorage = yield this.storageManager.get(this.name);
588
+ if (fromStorage && fromStorage.length !== 0) {
589
+ const __collection = new Collection(this.name);
590
+ __collection.insertMany(fromStorage);
591
+ const __data = __collection.find(where).map(x => x.toData());
592
+ if (__data.length !== 0) {
593
+ this.collection.insertMany(__data);
594
+ this.updateTotal(__data.length);
595
+ yield this.commit();
596
+ return;
597
+ }
598
+ }
580
599
  // If the storage manager is empty, fetch the data from the server.
581
600
  try {
582
601
  this.loading = true;
583
- const [_data, total] = yield this.fetchAll();
602
+ const [_data, total] = yield this.fetch(where);
584
603
  this.collection.insertMany(_data);
585
604
  this.updateTotal(total);
586
- yield this.commit();
587
605
  }
588
606
  catch (error) {
589
607
  this.error = error;
590
608
  }
591
609
  finally {
592
610
  this.loading = false;
611
+ yield this.commit();
593
612
  }
594
613
  });
595
614
  }
@@ -606,7 +625,7 @@ class Controller {
606
625
  * unsubscribe();
607
626
  * ```
608
627
  */
609
- publish(onChange) {
628
+ subscribe(onChange) {
610
629
  this.subscribers.add(onChange);
611
630
  return () => this.subscribers.delete(onChange);
612
631
  }
@@ -615,12 +634,12 @@ class Controller {
615
634
  *
616
635
  * This is intentionally private: consumers should use `commit()` which computes the snapshot.
617
636
  */
618
- subscribe(model) {
637
+ publish(models) {
619
638
  return __awaiter(this, void 0, void 0, function* () {
620
639
  // Persist the full cache snapshot for hydration.
621
640
  yield this.storageManager.set(this.name, this.collection.find().map((doc) => doc.toModel()));
622
641
  this.subscribers.forEach((sub) => {
623
- sub(model);
642
+ sub(models);
624
643
  });
625
644
  });
626
645
  }
@@ -634,7 +653,7 @@ class Controller {
634
653
  commit() {
635
654
  return __awaiter(this, void 0, void 0, function* () {
636
655
  const models = this.collection.find().map((doc) => doc.toModel());
637
- yield this.subscribe(models);
656
+ yield this.publish(models);
638
657
  });
639
658
  }
640
659
  /**
@@ -642,8 +661,13 @@ class Controller {
642
661
  *
643
662
  * Subclasses typically use this inside `invalidate()`.
644
663
  */
645
- refetch() {
646
- return this.initialise();
664
+ update(where) {
665
+ return __awaiter(this, void 0, void 0, function* () {
666
+ const [response, total] = yield this.fetch(where);
667
+ this.collection.insertMany(response);
668
+ this.updateTotal(total);
669
+ yield this.commit();
670
+ });
647
671
  }
648
672
  /**
649
673
  * Invalidate the cache for this controller.
@@ -667,10 +691,11 @@ class Controller {
667
691
  void this.storageManager.delete(this.name);
668
692
  this.collection.clear();
669
693
  this.updateTotal(0);
670
- this.updatePageSize(-1);
694
+ this.updatePage(0);
695
+ this.updateLimit(10);
671
696
  this.error = null;
672
697
  this.loading = false;
673
- void this.subscribe([]);
698
+ void this.publish([]);
674
699
  }
675
700
  /**
676
701
  * Create a controller.
@@ -679,22 +704,22 @@ class Controller {
679
704
  * @param storageManager - where snapshots are persisted (defaults to no-op)
680
705
  * @param pageSize - optional pagination hint (userland)
681
706
  */
682
- constructor(name, { storageManager = new DefaultStorageManager("live-cache:"), pageSize = -1, invalidator = new DefaultInvalidator(), initialiseOnMount = true, }) {
707
+ constructor(name, { storageManager = new DefaultStorageManager("live-cache:"), pageSize = 10, invalidator = new DefaultInvalidator(), }) {
683
708
  this.subscribers = new Set();
684
709
  this.loading = false;
685
710
  this.error = null;
686
711
  this.total = -1;
687
- this.pageSize = -1;
712
+ this.page = 0;
713
+ this.limit = 10;
688
714
  this.abortController = null;
715
+ this.initialised = false;
689
716
  this.name = name;
690
717
  this.collection = new Collection(name);
691
718
  this.storageManager = storageManager;
692
- this.pageSize = pageSize;
719
+ this.page = 0;
720
+ this.limit = pageSize;
693
721
  this.invalidator = invalidator;
694
722
  this.invalidator.bind(this.invalidate.bind(this));
695
- if (initialiseOnMount) {
696
- this.initialise();
697
- }
698
723
  }
699
724
  }
700
725
 
@@ -947,12 +972,12 @@ class ObjectStore {
947
972
  /**
948
973
  * Initialise a controller once per store, even if multiple callers request it.
949
974
  */
950
- initialiseOnce(name) {
975
+ initialiseOnce(name, where) {
951
976
  const controller = this.get(name);
952
977
  const existing = this.initialisePromises.get(controller);
953
978
  if (existing)
954
979
  return existing;
955
- const promise = controller.initialise().finally(() => {
980
+ const promise = controller.initialise(where).finally(() => {
956
981
  if (this.initialisePromises.get(controller) === promise) {
957
982
  this.initialisePromises.delete(controller);
958
983
  }
@@ -1302,7 +1327,7 @@ function useRegister(controller, store = getDefaultObjectStore()) {
1302
1327
  */
1303
1328
  function useController(name, where, options) {
1304
1329
  var _a, _b, _c, _d;
1305
- const initialise = (_a = options === null || options === void 0 ? void 0 : options.initialise) !== null && _a !== void 0 ? _a : true;
1330
+ (_a = options === null || options === void 0 ? void 0 : options.initialise) !== null && _a !== void 0 ? _a : true;
1306
1331
  const optionalStore = options === null || options === void 0 ? void 0 : options.store;
1307
1332
  const abortOnUnmount = (_b = options === null || options === void 0 ? void 0 : options.abortOnUnmount) !== null && _b !== void 0 ? _b : true;
1308
1333
  const withInvalidation = (_c = options === null || options === void 0 ? void 0 : options.withInvalidation) !== null && _c !== void 0 ? _c : true;
@@ -1324,13 +1349,12 @@ function useController(name, where, options) {
1324
1349
  };
1325
1350
  // Prime state immediately.
1326
1351
  callback();
1327
- const cleanup = controller.publish(callback);
1352
+ const cleanup = controller.subscribe(callback);
1328
1353
  if (withInvalidation) {
1329
1354
  controller.invalidator.registerInvalidation();
1330
1355
  }
1331
- if (initialise) {
1332
- void store.initialiseOnce(name);
1333
- }
1356
+ void store.initialiseOnce(name, where);
1357
+ // controller.initialise(where);
1334
1358
  return () => {
1335
1359
  if (abortOnUnmount) {
1336
1360
  controller.abort();
@@ -1338,7 +1362,7 @@ function useController(name, where, options) {
1338
1362
  cleanup();
1339
1363
  controller.invalidator.unregisterInvalidation();
1340
1364
  };
1341
- }, [controller, where, initialise, abortOnUnmount, withInvalidation]);
1365
+ }, [controller, where, abortOnUnmount, withInvalidation]);
1342
1366
  return { controller, data, loading, error };
1343
1367
  }
1344
1368
 
@@ -1361,7 +1385,7 @@ function useJoinController({ from, where, select }) {
1361
1385
  setData(join(from, where, select));
1362
1386
  };
1363
1387
  callback();
1364
- const cleanup = from.map((c) => c.publish(callback));
1388
+ const cleanup = from.map((c) => c.subscribe(callback));
1365
1389
  return () => {
1366
1390
  cleanup.forEach((c) => c());
1367
1391
  };