shelving 1.18.0 → 1.20.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.
Files changed (111) hide show
  1. package/db/Change.d.ts +16 -18
  2. package/db/Change.js +7 -13
  3. package/db/Database.d.ts +59 -45
  4. package/db/Database.js +52 -44
  5. package/db/Pagination.d.ts +19 -11
  6. package/db/Pagination.js +49 -32
  7. package/db/errors.d.ts +12 -12
  8. package/error/ConditionError.d.ts +7 -0
  9. package/error/ConditionError.js +10 -0
  10. package/error/index.d.ts +1 -0
  11. package/error/index.js +1 -0
  12. package/firestore/client/FirestoreClientProvider.d.ts +9 -9
  13. package/firestore/lite/FirestoreLiteProvider.d.ts +7 -7
  14. package/firestore/server/FirestoreServerProvider.d.ts +9 -9
  15. package/package.json +8 -8
  16. package/provider/BatchProvider.d.ts +7 -7
  17. package/provider/BatchProvider.js +16 -12
  18. package/provider/CacheProvider.d.ts +14 -14
  19. package/provider/CacheProvider.js +11 -20
  20. package/provider/MemoryProvider.d.ts +10 -10
  21. package/provider/MemoryProvider.js +1 -1
  22. package/provider/Provider.d.ts +22 -22
  23. package/provider/ThroughProvider.d.ts +13 -13
  24. package/provider/ValidationProvider.d.ts +10 -10
  25. package/provider/ValidationProvider.js +5 -19
  26. package/query/Query.d.ts +1 -1
  27. package/query/Query.js +2 -2
  28. package/react/index.d.ts +2 -2
  29. package/react/index.js +2 -2
  30. package/react/{useResult.d.ts → useDocument.d.ts} +5 -5
  31. package/react/{useResult.js → useDocument.js} +6 -8
  32. package/react/{useData.d.ts → useDocumentData.d.ts} +5 -5
  33. package/react/useDocumentData.js +9 -0
  34. package/react/useFetch.d.ts +1 -1
  35. package/react/useFetch.js +2 -3
  36. package/react/usePagination.d.ts +2 -2
  37. package/react/useQuery.d.ts +8 -7
  38. package/react/useQuery.js +13 -14
  39. package/react/useSubscribe.js +2 -2
  40. package/schema/AllowSchema.d.ts +29 -0
  41. package/schema/AllowSchema.js +39 -0
  42. package/schema/ArraySchema.js +1 -1
  43. package/schema/DataSchema.d.ts +1 -1
  44. package/schema/DataSchema.js +1 -1
  45. package/schema/MapSchema.d.ts +0 -1
  46. package/schema/MapSchema.js +6 -6
  47. package/schema/NumberSchema.d.ts +0 -2
  48. package/schema/ObjectSchema.d.ts +1 -2
  49. package/schema/ObjectSchema.js +2 -2
  50. package/schema/StringSchema.d.ts +1 -3
  51. package/schema/StringSchema.js +1 -2
  52. package/schema/index.d.ts +1 -1
  53. package/schema/index.js +1 -1
  54. package/stream/ArrayState.d.ts +1 -0
  55. package/stream/ArrayState.js +5 -0
  56. package/stream/State.d.ts +38 -17
  57. package/stream/State.js +66 -20
  58. package/stream/Stream.d.ts +56 -7
  59. package/stream/Stream.js +114 -8
  60. package/stream/index.d.ts +0 -6
  61. package/stream/index.js +0 -6
  62. package/test/basics.js +2 -2
  63. package/util/assert.d.ts +4 -2
  64. package/util/assert.js +7 -2
  65. package/util/async.d.ts +41 -0
  66. package/util/async.js +71 -0
  67. package/util/constants.d.ts +3 -3
  68. package/util/constants.js +3 -3
  69. package/util/data.d.ts +114 -4
  70. package/util/data.js +62 -3
  71. package/util/derive.d.ts +0 -3
  72. package/util/derive.js +4 -12
  73. package/util/diff.d.ts +3 -3
  74. package/util/dispatch.d.ts +3 -3
  75. package/util/dispatch.js +5 -15
  76. package/util/equal.d.ts +2 -2
  77. package/util/equal.js +5 -2
  78. package/util/error.d.ts +0 -4
  79. package/util/hydrate.js +3 -2
  80. package/util/index.d.ts +2 -2
  81. package/util/index.js +2 -2
  82. package/util/{iterable.d.ts → iterate.d.ts} +45 -18
  83. package/util/{iterable.js → iterate.js} +72 -13
  84. package/util/map.d.ts +2 -3
  85. package/util/map.js +2 -2
  86. package/util/merge.d.ts +7 -4
  87. package/util/merge.js +7 -5
  88. package/util/object.d.ts +7 -114
  89. package/util/object.js +3 -60
  90. package/util/observable.d.ts +57 -9
  91. package/util/observable.js +132 -44
  92. package/util/string.js +2 -2
  93. package/util/validate.d.ts +4 -2
  94. package/util/validate.js +2 -3
  95. package/react/useData.js +0 -9
  96. package/schema/AllowedSchema.d.ts +0 -17
  97. package/schema/AllowedSchema.js +0 -28
  98. package/stream/AbstractState.d.ts +0 -35
  99. package/stream/AbstractState.js +0 -84
  100. package/stream/AbstractStream.d.ts +0 -66
  101. package/stream/AbstractStream.js +0 -123
  102. package/stream/DeriveStream.d.ts +0 -12
  103. package/stream/DeriveStream.js +0 -29
  104. package/stream/LimitStream.d.ts +0 -13
  105. package/stream/LimitStream.js +0 -26
  106. package/stream/ValidateStream.d.ts +0 -8
  107. package/stream/ValidateStream.js +0 -18
  108. package/stream/errors.d.ts +0 -4
  109. package/stream/errors.js +0 -6
  110. package/util/promise.d.ts +0 -14
  111. package/util/promise.js +0 -27
package/db/Pagination.js CHANGED
@@ -1,60 +1,77 @@
1
- import { getFirstItem, getLastItem, assertLength, assertNumber, yieldMerged } from "../util/index.js";
2
- import { AbstractState, StreamClosedError } from "../stream/index.js";
1
+ import { getFirstItem, getLastItem, assertLength, assertNumber, yieldMerged, toMap } from "../util/index.js";
2
+ import { State } from "../stream/index.js";
3
+ import { ConditionError } from "../index.js";
3
4
  /**
4
5
  * State that wraps a `Documents` reference to enable pagination.
5
6
  * - If you pass in initial values, it will use that as the first page.
6
7
  * - If you don't pass in initial values, it will autoload the first page.
7
8
  */
8
- export class Pagination extends AbstractState {
9
+ export class Pagination extends State {
9
10
  constructor(ref) {
10
11
  super();
11
- this._pending = false;
12
+ this.startLoading = false;
13
+ this.startDone = false;
14
+ this.endLoading = false;
15
+ this.endDone = false;
12
16
  /**
13
17
  * Load more results before the start.
14
18
  * - Promise that needs to be handled.
15
19
  */
16
- this.backward = async () => {
20
+ this.loadStart = async () => {
17
21
  if (this.closed)
18
- throw new StreamClosedError();
19
- if (!this._pending) {
20
- const entry = getFirstItem(this.value);
21
- this._pending = true;
22
- this.next(await (entry ? this.ref.before(entry[0], entry[1]).results : this.ref.results));
22
+ throw new ConditionError();
23
+ if (!this.startLoading) {
24
+ this.startLoading = true;
25
+ if (!this.loading) {
26
+ const firstItem = getFirstItem(this.value);
27
+ if (firstItem) {
28
+ const next = await this.ref.after(firstItem[0], firstItem[1]).resultsMap;
29
+ this.startDone = next.size < this.limit;
30
+ this.startLoading = false;
31
+ return this.merge(next);
32
+ }
33
+ }
34
+ const next = await this.ref.resultsMap;
35
+ this.startDone = next.size < this.limit;
36
+ this.startLoading = false;
37
+ return this.next(next);
23
38
  }
24
39
  };
25
40
  /**
26
41
  * Load more results after the end.
27
42
  * - Promise that needs to be handled.
28
43
  */
29
- this.forward = async () => {
44
+ this.loadEnd = async () => {
30
45
  if (this.closed)
31
- throw new StreamClosedError();
32
- if (!this._pending) {
33
- const entry = getLastItem(this.value);
34
- this._pending = true;
35
- this.next(await (entry ? this.ref.after(entry[0], entry[1]).results : this.ref.results));
46
+ throw new ConditionError();
47
+ if (!this.endLoading) {
48
+ this.endLoading = true;
49
+ if (!this.loading) {
50
+ const lastItem = getLastItem(this.value);
51
+ if (lastItem) {
52
+ const next = await this.ref.after(lastItem[0], lastItem[1]).resultsMap;
53
+ this.endDone = next.size < this.limit;
54
+ this.endLoading = false;
55
+ return this.merge(next);
56
+ }
57
+ }
58
+ const next = await this.ref.resultsMap;
59
+ this.endDone = next.size < this.limit;
60
+ this.endLoading = false;
61
+ return this.next(next);
36
62
  }
37
63
  };
38
64
  this.ref = ref;
39
65
  assertNumber(ref.limit); // Collection must have a numeric limit to paginate (otherwise you'd be retrieving the entire set of documents).
40
66
  assertLength(ref.sorts, 1, Infinity); // Collection must have at least one sort order to paginate.
67
+ this.limit = ref.limit;
41
68
  }
42
- // Dispatch doesn't just dispatch the next value, it merges it into the current results and dispatches the combined results.
43
- _derive(results) {
44
- this._pending = false;
45
- if (this.loading) {
46
- // Merge the results into the existing results.
47
- const current = this.value;
48
- const next = new Map(this.ref.sorts.derive(yieldMerged(this.value, results)));
49
- const change = next.size - current.size;
50
- super._dispatch(next);
51
- // Automatically complete the pagination if there are fewer entries than the slice limit.
52
- if (typeof this.ref.limit === "number" && change < this.ref.limit)
53
- this.complete();
54
- }
55
- else {
56
- super._dispatch(new Map(results));
57
- }
69
+ /**
70
+ * Merge more results into this pagination.
71
+ * @return The change in the number of results.
72
+ */
73
+ merge(more) {
74
+ this.next(toMap(this.ref.sorts.derive(yieldMerged(more, this.value))));
58
75
  }
59
76
  /** Iterate over the entries of the values currently in the pagination. */
60
77
  [Symbol.iterator]() {
package/db/errors.d.ts CHANGED
@@ -1,19 +1,19 @@
1
- import type { Datas, Key } from "../util/index.js";
1
+ import type { Data } from "../util/index.js";
2
2
  import { RequiredError, ValidationError } from "../error/index.js";
3
- import { Feedback } from "../feedback/index.js";
4
- import type { DatabaseDocument, DatabaseQuery } from "./Database.js";
3
+ import type { Feedback } from "../feedback/index.js";
4
+ import type { DataDocument, DataQuery } from "./Database.js";
5
5
  /** Thrown if a document doesn't exist. */
6
- export declare class DocumentRequiredError<D extends Datas, C extends Key<D>> extends RequiredError {
7
- ref: DatabaseDocument<D, C>;
8
- constructor(ref: DatabaseDocument<D, C>);
6
+ export declare class DocumentRequiredError<T extends Data> extends RequiredError {
7
+ ref: DataDocument<T>;
8
+ constructor(ref: DataDocument<T>);
9
9
  }
10
10
  /** Thrown if a document can't validate. */
11
- export declare class DocumentValidationError<D extends Datas, C extends Key<D>> extends ValidationError {
12
- ref: DatabaseDocument<D, C>;
13
- constructor(ref: DatabaseDocument<D, C>, feedback: Feedback);
11
+ export declare class DocumentValidationError<T extends Data> extends ValidationError {
12
+ ref: DataDocument<T>;
13
+ constructor(ref: DataDocument<T>, feedback: Feedback);
14
14
  }
15
15
  /** Thrown if a query can't validate a set of results. */
16
- export declare class QueryValidationError<D extends Datas, C extends Key<D>> extends ValidationError {
17
- ref: DatabaseQuery<D, C>;
18
- constructor(ref: DatabaseQuery<D, C>, feedback: Feedback);
16
+ export declare class QueryValidationError<T extends Data> extends ValidationError {
17
+ ref: DataQuery<T>;
18
+ constructor(ref: DataQuery<T>, feedback: Feedback);
19
19
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Thrown if the program is in a condition it shouldn't have reached.
3
+ * e.g. writing to a stream that's already closed
4
+ */
5
+ export declare class ConditionError extends Error {
6
+ constructor(message?: string);
7
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Thrown if the program is in a condition it shouldn't have reached.
3
+ * e.g. writing to a stream that's already closed
4
+ */
5
+ export class ConditionError extends Error {
6
+ constructor(message = "Invalid condition") {
7
+ super(message);
8
+ }
9
+ }
10
+ ConditionError.prototype.name = "ConditionError";
package/error/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export * from "./PermissionError.js";
3
3
  export * from "./RequiredError.js";
4
4
  export * from "./UnsupportedError.js";
5
5
  export * from "./ValidationError.js";
6
+ export * from "./ConditionError.js";
package/error/index.js CHANGED
@@ -3,3 +3,4 @@ export * from "./PermissionError.js";
3
3
  export * from "./RequiredError.js";
4
4
  export * from "./UnsupportedError.js";
5
5
  export * from "./ValidationError.js";
6
+ export * from "./ConditionError.js";
@@ -1,19 +1,19 @@
1
1
  import type { Firestore } from "firebase/firestore";
2
- import { Results, Provider, DatabaseDocument, DatabaseQuery, Result, Observer, Transform, AsynchronousProvider, Datas, Key } from "../../index.js";
2
+ import { Results, Provider, DataDocument, DataQuery, Result, Observer, Transform, AsynchronousProvider, Data } from "../../index.js";
3
3
  /**
4
4
  * Firestore client database provider.
5
5
  * - Works with the Firebase JS SDK.
6
6
  * - Supports offline mode.
7
7
  * - Supports realtime subscriptions.
8
8
  */
9
- export declare class FirestoreClientProvider<D extends Datas> extends Provider<D> implements AsynchronousProvider<D> {
9
+ export declare class FirestoreClientProvider extends Provider implements AsynchronousProvider {
10
10
  readonly firestore: Firestore;
11
11
  constructor(firestore: Firestore);
12
- get<C extends Key<D>>(ref: DatabaseDocument<D, C>): Promise<Result<D[C]>>;
13
- subscribe<C extends Key<D>>(ref: DatabaseDocument<D, C>, observer: Observer<Result<D[C]>>): () => void;
14
- add<C extends Key<D>>(ref: DatabaseQuery<D, C>, data: D[C]): Promise<string>;
15
- write<C extends Key<D>>(ref: DatabaseDocument<D, C>, value: D[C] | Transform<D[C]> | undefined): Promise<void>;
16
- getQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>): Promise<Results<D[C]>>;
17
- subscribeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, observer: Observer<Results<D[C]>>): () => void;
18
- writeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, value: D[C] | Transform<D[C]> | undefined): Promise<void>;
12
+ get<T extends Data>(ref: DataDocument<T>): Promise<Result<T>>;
13
+ subscribe<T extends Data>(ref: DataDocument<T>, observer: Observer<Result<T>>): () => void;
14
+ add<T extends Data>(ref: DataQuery<T>, data: T): Promise<string>;
15
+ write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): Promise<void>;
16
+ getQuery<T extends Data>(ref: DataQuery<T>): Promise<Results<T>>;
17
+ subscribeQuery<T extends Data>(ref: DataQuery<T>, observer: Observer<Results<T>>): () => void;
18
+ writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): Promise<void>;
19
19
  }
@@ -1,19 +1,19 @@
1
1
  import type { Firestore } from "firebase/firestore/lite";
2
- import { Results, Provider, DatabaseDocument, DatabaseQuery, Result, Transform, AsynchronousProvider, Datas, Key } from "../../index.js";
2
+ import { Provider, DataDocument, DataQuery, Result, Transform, AsynchronousProvider, Data, Results } from "../../index.js";
3
3
  /**
4
4
  * Firestore Lite client database provider.
5
5
  * - Works with the Firebase JS SDK.
6
6
  * - Does not support offline mode.
7
7
  * - Does not support realtime subscriptions.
8
8
  */
9
- export declare class FirestoreClientProvider<D extends Datas> extends Provider<D> implements AsynchronousProvider<D> {
9
+ export declare class FirestoreClientProvider extends Provider implements AsynchronousProvider {
10
10
  readonly firestore: Firestore;
11
11
  constructor(firestore: Firestore);
12
- get<C extends Key<D>>(ref: DatabaseDocument<D, C>): Promise<Result<D[C]>>;
12
+ get<T extends Data>(ref: DataDocument<T>): Promise<Result<T>>;
13
13
  subscribe(): () => void;
14
- add<C extends Key<D>>(ref: DatabaseQuery<D, C>, data: D[C]): Promise<string>;
15
- write<C extends Key<D>>(ref: DatabaseDocument<D, C>, value: D[C] | Transform<D[C]> | undefined): Promise<void>;
16
- getQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>): Promise<Results<D[C]>>;
14
+ add<T extends Data>(ref: DataQuery<T>, data: T): Promise<string>;
15
+ write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): Promise<void>;
16
+ getQuery<T extends Data>(ref: DataQuery<T>): Promise<Results<T>>;
17
17
  subscribeQuery(): () => void;
18
- writeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, value: D[C] | Transform<D[C]> | undefined): Promise<void>;
18
+ writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): Promise<void>;
19
19
  }
@@ -1,17 +1,17 @@
1
1
  import { Firestore } from "@google-cloud/firestore";
2
- import { Results, Provider, DatabaseDocument, DatabaseQuery, Observer, Result, Transform, AsynchronousProvider, Datas, Key, Entry } from "../../index.js";
2
+ import { Provider, DataDocument, DataQuery, Observer, Result, Transform, Data, AsynchronousProvider, Entry, Results } from "../../index.js";
3
3
  /**
4
4
  * Firestore server database provider.
5
5
  * - Works with the Firebase Admin SDK for Node.JS
6
6
  */
7
- export declare class FirestoreServerProvider<D extends Datas> extends Provider<D> implements AsynchronousProvider<D> {
7
+ export declare class FirestoreServerProvider extends Provider implements AsynchronousProvider {
8
8
  readonly firestore: Firestore;
9
9
  constructor(firestore?: Firestore);
10
- get<C extends Key<D>>(ref: DatabaseDocument<D, C>): Promise<Result<D[C]>>;
11
- subscribe<C extends Key<D>>(ref: DatabaseDocument<D, C>, observer: Observer<Result<D[C]>>): () => void;
12
- add<C extends Key<D>>(ref: DatabaseQuery<D, C>, data: D[C]): Promise<string>;
13
- write<C extends Key<D>>(ref: DatabaseDocument<D, C>, value: D[C] | Transform<D[C]> | undefined): Promise<void>;
14
- getQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>): Promise<Iterable<Entry<D[C]>>>;
15
- subscribeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, observer: Observer<Results<D[C]>>): () => void;
16
- writeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, value: D[C] | Transform<D[C]> | undefined): Promise<void>;
10
+ get<T extends Data>(ref: DataDocument<T>): Promise<Result<T>>;
11
+ subscribe<T extends Data>(ref: DataDocument<T>, observer: Observer<Result<T>>): () => void;
12
+ add<T extends Data>(ref: DataQuery<T>, data: T): Promise<string>;
13
+ write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): Promise<void>;
14
+ getQuery<T extends Data>(ref: DataQuery<T>): Promise<Iterable<Entry<T>>>;
15
+ subscribeQuery<T extends Data>(ref: DataQuery<T>, observer: Observer<Results<T>>): () => void;
16
+ writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): Promise<void>;
17
17
  }
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.18.0",
14
+ "version": "1.20.2",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -61,18 +61,18 @@
61
61
  "@types/jest": "^27.0.3",
62
62
  "@types/react": "^17.0.37",
63
63
  "@types/react-dom": "^17.0.11",
64
- "@typescript-eslint/eslint-plugin": "^5.4.0",
65
- "@typescript-eslint/parser": "^5.4.0",
64
+ "@typescript-eslint/eslint-plugin": "^5.5.0",
65
+ "@typescript-eslint/parser": "^5.5.0",
66
+ "eslint": "^8.4.0",
66
67
  "eslint-config-prettier": "^8.3.0",
67
68
  "eslint-plugin-import": "^2.25.3",
68
69
  "eslint-plugin-prettier": "^4.0.0",
69
- "eslint": "^8.3.0",
70
- "firebase": "^9.5.0",
70
+ "firebase": "^9.6.0",
71
+ "jest": "^27.4.3",
71
72
  "jest-ts-webcompat-resolver": "^1.0.0",
72
- "jest": "^27.3.1",
73
- "prettier": "^2.5.0",
74
- "react-dom": "^17.0.2",
73
+ "prettier": "^2.5.1",
75
74
  "react": "^17.0.2",
75
+ "react-dom": "^17.0.2",
76
76
  "ts-jest": "^27.0.7",
77
77
  "typescript": "^4.5.2"
78
78
  },
@@ -1,5 +1,5 @@
1
- import { MutableObject, Result, Results, Observer, Unsubscriber, Observable, Datas, Key } from "../util/index.js";
2
- import type { DatabaseDocument, DatabaseQuery } from "../db/index.js";
1
+ import { MutableObject, Result, Observer, Unsubscriber, Observable, Results, ResultsMap, Data } from "../util/index.js";
2
+ import type { DataDocument, DataQuery } from "../db/index.js";
3
3
  import { ThroughProvider } from "./ThroughProvider.js";
4
4
  /**
5
5
  * Provider that batches multiple database reads from a source provider together, for efficiency.
@@ -10,17 +10,17 @@ import { ThroughProvider } from "./ThroughProvider.js";
10
10
  *
11
11
  * Basically makes any provider under it more efficient.
12
12
  */
13
- export declare class BatchProvider<D extends Datas> extends ThroughProvider<D> {
13
+ export declare class BatchProvider extends ThroughProvider {
14
14
  /** List of currently ongoing get requests. */
15
15
  protected readonly _gets: MutableObject<Promise<any>>;
16
16
  /** List of currently ongoing subscription streams. */
17
17
  protected readonly _subs: MutableObject<Observable<any>>;
18
- get<C extends Key<D>>(ref: DatabaseDocument<D, C>): Result<D[C]> | Promise<Result<D[C]>>;
18
+ get<T extends Data>(ref: DataDocument<T>): Result<T> | Promise<Result<T>>;
19
19
  /** Await a result and delete it from get requests when done. */
20
20
  private _awaitDocument;
21
- subscribe<C extends Key<D>>(ref: DatabaseDocument<D, C>, observer: Observer<Result<D[C]>>): Unsubscriber;
22
- getQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>): Results<D[C]> | Promise<Results<D[C]>>;
21
+ subscribe<T extends Data>(ref: DataDocument<T>, observer: Observer<Result<T>>): Unsubscriber;
22
+ getQuery<T extends Data>(ref: DataQuery<T>): Results<T> | Promise<Results<T>>;
23
23
  /** Await a set of results and delete from get requests when done. */
24
24
  private _awaitDocuments;
25
- subscribeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, observer: Observer<Results<D[C]>>): Unsubscriber;
25
+ subscribeQuery<T extends Data>(ref: DataQuery<T>, observer: Observer<ResultsMap<T>>): Unsubscriber;
26
26
  }
@@ -1,5 +1,5 @@
1
- import { isAsync } from "../util/index.js";
2
- import { getNextValue, LazyState, subscribeState } from "../stream/index.js";
1
+ import { isAsync, toMap, DeriveObserver, awaitNext, } from "../util/index.js";
2
+ import { LazyState } from "../stream/index.js";
3
3
  import { ThroughProvider } from "./ThroughProvider.js";
4
4
  /** How long to wait after all subscriptions have ended to close the source subscription. */
5
5
  const STOP_DELAY = 2000;
@@ -42,15 +42,16 @@ export class BatchProvider extends ThroughProvider {
42
42
  const key = ref.toString();
43
43
  // TidyState completes itself `STOP_DELAY` milliseconds after its last observer unsubscribes.
44
44
  // States also send their most recently received value to any new observers.
45
- const sub = ((_a = this._subs)[key] || (_a[key] = subscribeState(s => {
45
+ const sub = ((_a = this._subs)[key] || (_a[key] = new LazyState(STOP_DELAY).from(s => {
46
46
  var _a;
47
47
  const stop = super.subscribe(ref, s);
48
- (_a = this._gets)[key] || (_a[key] = this._awaitDocument(ref, getNextValue(sub))); // The first value from the new subscription can be reused for any concurrent get requests.
48
+ // The first value from the new subscription can be reused for any concurrent get requests.
49
+ (_a = this._gets)[key] || (_a[key] = this._awaitDocument(ref, awaitNext(sub)));
49
50
  return () => {
50
51
  delete this._subs[key];
51
52
  stop();
52
53
  };
53
- }, new LazyState(STOP_DELAY))));
54
+ })));
54
55
  return sub.subscribe(observer);
55
56
  }
56
57
  // Override to combine multiple requests into one.
@@ -63,11 +64,12 @@ export class BatchProvider extends ThroughProvider {
63
64
  return isAsync(result) ? (this._gets[key] = this._awaitDocuments(ref, result)) : result;
64
65
  }
65
66
  /** Await a set of results and delete from get requests when done. */
66
- async _awaitDocuments(ref, asyncResult) {
67
- const result = await asyncResult;
67
+ async _awaitDocuments(ref, asyncResults) {
68
+ // Convert the iterable to a map because it might be read multiple times.
69
+ const results = toMap(await asyncResults);
68
70
  const key = ref.toString();
69
71
  delete this._gets[key];
70
- return result;
72
+ return results;
71
73
  }
72
74
  // Override to combine multiple subscriptions into one.
73
75
  subscribeQuery(ref, observer) {
@@ -75,15 +77,17 @@ export class BatchProvider extends ThroughProvider {
75
77
  const key = ref.toString();
76
78
  // TidyState completes itself `STOP_DELAY` milliseconds after its last observer unsubscribes.
77
79
  // States also send their most recently received value to any new observers.
78
- const sub = ((_a = this._subs)[key] || (_a[key] = subscribeState(s => {
80
+ const sub = ((_a = this._subs)[key] || (_a[key] = new LazyState(STOP_DELAY).from(o => {
79
81
  var _a;
80
- const stop = super.subscribeQuery(ref, s);
81
- (_a = this._gets)[key] || (_a[key] = this._awaitDocuments(ref, getNextValue(sub))); // The first value from the subscription can be reused for any concurrent get requests.
82
+ // Convert the iterable to a map because it might be read multiple times.
83
+ const stop = super.subscribeQuery(ref, new DeriveObserver(toMap, o));
84
+ // The first value from the subscription can be reused for any concurrent get requests.
85
+ (_a = this._gets)[key] || (_a[key] = this._awaitDocuments(ref, awaitNext(sub)));
82
86
  return () => {
83
87
  delete this._subs[key];
84
88
  stop();
85
89
  };
86
- }, new LazyState(STOP_DELAY))));
90
+ })));
87
91
  return sub.subscribe(observer);
88
92
  }
89
93
  }
@@ -1,31 +1,31 @@
1
- import type { DatabaseDocument, DatabaseQuery } from "../db/index.js";
1
+ import type { DataDocument, DataQuery } from "../db/index.js";
2
2
  import { Transform } from "../transform/index.js";
3
- import type { Result, Results, Unsubscriber, Observer, Datas, Key } from "../util/index.js";
3
+ import { Result, Unsubscriber, Observer, Results, Data } from "../util/index.js";
4
4
  import type { Provider, AsynchronousProvider } from "./Provider.js";
5
5
  import { MemoryProvider } from "./MemoryProvider.js";
6
6
  import { ThroughProvider } from "./ThroughProvider.js";
7
7
  /** Keep a copy of received data in a local cache. */
8
- export declare class CacheProvider<D extends Datas> extends ThroughProvider<D> implements AsynchronousProvider<D> {
8
+ export declare class CacheProvider extends ThroughProvider implements AsynchronousProvider {
9
9
  /** The local cache provider. */
10
- readonly cache: MemoryProvider<D>;
10
+ readonly cache: MemoryProvider;
11
11
  /** Last-known-correct time for data, indexed by key to power `getCachedAge()` etc. */
12
12
  private _times;
13
- constructor(source: Provider<D>, cache?: MemoryProvider<D>);
13
+ constructor(source: Provider, cache?: MemoryProvider);
14
14
  /** Is a given document or query in the cache? */
15
- isCached<C extends Key<D>>(ref: DatabaseDocument<D, C> | DatabaseQuery<D, C>): boolean;
15
+ isCached<T extends Data>(ref: DataDocument<T> | DataQuery<T>): boolean;
16
16
  /** Get the cache age for a given document or query reference. */
17
- getCachedAge<C extends Key<D>>(ref: DatabaseDocument<D, C> | DatabaseQuery<D, C>): number;
17
+ getCachedAge<T extends Data>(ref: DataDocument<T> | DataQuery<T>): number;
18
18
  /** Cache an individual document result. */
19
19
  private _cacheResult;
20
- get<C extends Key<D>>(ref: DatabaseDocument<D, C>): Promise<Result<D[C]>>;
21
- subscribe<C extends Key<D>>(ref: DatabaseDocument<D, C>, observer: Observer<Result<D[C]>>): Unsubscriber;
22
- add<C extends Key<D>>(ref: DatabaseQuery<D, C>, data: D[C]): Promise<string>;
23
- write<C extends Key<D>>(ref: DatabaseDocument<D, C>, value: D[C] | Transform<D[C]> | undefined): Promise<void>;
20
+ get<T extends Data>(ref: DataDocument<T>): Promise<Result<T>>;
21
+ subscribe<T extends Data>(ref: DataDocument<T>, observer: Observer<Result<T>>): Unsubscriber;
22
+ add<T extends Data>(ref: DataQuery<T>, data: T): Promise<string>;
23
+ write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): Promise<void>;
24
24
  /** Cache a set of document results. */
25
25
  private _cacheResults;
26
- getQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>): Promise<Results<D[C]>>;
27
- subscribeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, observer: Observer<Results<D[C]>>): Unsubscriber;
28
- writeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, value: D[C] | Transform<D[C]> | undefined): Promise<void>;
26
+ getQuery<T extends Data>(ref: DataQuery<T>): Promise<Results<T>>;
27
+ subscribeQuery<T extends Data>(ref: DataQuery<T>, observer: Observer<Results<T>>): Unsubscriber;
28
+ writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): Promise<void>;
29
29
  /** Reset this provider and clear all data. */
30
30
  reset(): void;
31
31
  }
@@ -1,5 +1,5 @@
1
1
  import { Transform } from "../transform/index.js";
2
- import { Stream } from "../stream/index.js";
2
+ import { DeriveObserver } from "../util/index.js";
3
3
  import { MemoryProvider } from "./MemoryProvider.js";
4
4
  import { ThroughProvider } from "./ThroughProvider.js";
5
5
  /** Keep a copy of received data in a local cache. */
@@ -23,23 +23,17 @@ export class CacheProvider extends ThroughProvider {
23
23
  }
24
24
  /** Cache an individual document result. */
25
25
  _cacheResult(ref, result) {
26
- // Set or delete the result in the cache.
27
26
  this.cache.write(ref, result);
28
- // Save the last-cached time.
29
27
  this._times[ref.toString()] = Date.now();
28
+ return result;
30
29
  }
31
30
  // Override to cache any got result.
32
31
  async get(ref) {
33
- const result = await super.get(ref);
34
- this._cacheResult(ref, result);
35
- return result;
32
+ return this._cacheResult(ref, await super.get(ref));
36
33
  }
37
34
  // Override to cache any got results.
38
35
  subscribe(ref, observer) {
39
- const stream = new Stream();
40
- stream.on({ next: r => this._cacheResult(ref, r) });
41
- stream.on(observer);
42
- return super.subscribe(ref, stream);
36
+ return super.subscribe(ref, new DeriveObserver(result => this._cacheResult(ref, result), observer));
43
37
  }
44
38
  async add(ref, data) {
45
39
  const id = await super.add(ref, data);
@@ -56,7 +50,7 @@ export class CacheProvider extends ThroughProvider {
56
50
  this.cache.write(ref, value);
57
51
  }
58
52
  /** Cache a set of document results. */
59
- _cacheResults(ref, results) {
53
+ *_cacheResults(ref, results) {
60
54
  // We know the received set of results is the 'complete' set of results for this query.
61
55
  // So for correctness any documents matching this query that aren't in the new set of results should be deleted.
62
56
  // None of this applies if there's a query limit, because the document could have been moved to a different page so shouldn't be deleted.
@@ -64,24 +58,21 @@ export class CacheProvider extends ThroughProvider {
64
58
  for (const id of Object.keys(this.cache.getQuery(ref)))
65
59
  if (!(id in results))
66
60
  this.cache.write(ref.doc(id), undefined);
67
- // Save the new results to the cache.
68
- for (const [id, data] of Object.entries(results))
61
+ // Save new results to the cache.
62
+ for (const [id, data] of results) {
69
63
  this.cache.write(ref.doc(id), data);
64
+ yield [id, data];
65
+ }
70
66
  // Save the last-cached time.
71
67
  this._times[ref.toString()] = Date.now();
72
68
  }
73
69
  // Override to cache any got results.
74
70
  async getQuery(ref) {
75
- const results = await super.getQuery(ref);
76
- this._cacheResults(ref, results);
77
- return results;
71
+ return this._cacheResults(ref, await super.getQuery(ref));
78
72
  }
79
73
  // Override to cache any got results.
80
74
  subscribeQuery(ref, observer) {
81
- const stream = new Stream();
82
- stream.on({ next: r => this._cacheResults(ref, r) });
83
- stream.on(observer);
84
- return super.subscribeQuery(ref, stream);
75
+ return super.subscribeQuery(ref, new DeriveObserver(results => this._cacheResults(ref, results), observer));
85
76
  }
86
77
  async writeQuery(ref, value) {
87
78
  await super.writeQuery(ref, value);
@@ -1,23 +1,23 @@
1
- import { Result, Results, Unsubscriber, Observer, Datas, Key } from "../util/index.js";
1
+ import { Data, Result, Results, Unsubscriber, Observer } from "../util/index.js";
2
2
  import { Transform } from "../transform/index.js";
3
- import { DatabaseQuery, DatabaseDocument } from "../db/index.js";
3
+ import { DataQuery, DataDocument } from "../db/index.js";
4
4
  import { Provider, SynchronousProvider } from "./Provider.js";
5
5
  /**
6
6
  * Fast in-memory store for data.
7
7
  * - Extremely fast (ideal for caching!), but does not persist data after the browser window is closed.
8
8
  * - `get()` etc return the exact same instance of an object that's passed into `set()`
9
9
  */
10
- export declare class MemoryProvider<D extends Datas> extends Provider<D> implements SynchronousProvider<D> {
10
+ export declare class MemoryProvider extends Provider implements SynchronousProvider {
11
11
  /** List of tables in `{ path: Table }` format. */
12
12
  private _tables;
13
13
  private _table;
14
- get<C extends Key<D>>(ref: DatabaseDocument<D, C>): Result<D[C]>;
15
- subscribe<C extends Key<D>>(ref: DatabaseDocument<D, C>, observer: Observer<Result<D[C]>>): Unsubscriber;
16
- add<C extends Key<D>>(ref: DatabaseQuery<D, C>, data: D[C]): string;
17
- write<C extends Key<D>>(ref: DatabaseDocument<D, C>, value: D[C] | Transform<D[C]> | undefined): void;
18
- getQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>): Results<D[C]>;
19
- subscribeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, observer: Observer<Results<D[C]>>): Unsubscriber;
20
- writeQuery<C extends Key<D>>(ref: DatabaseQuery<D, C>, value: D[C] | Transform<D[C]> | undefined): void;
14
+ get<T extends Data>(ref: DataDocument<T>): Result<T>;
15
+ subscribe<T extends Data>(ref: DataDocument<T>, observer: Observer<Result<T>>): Unsubscriber;
16
+ add<T extends Data>(ref: DataQuery<T>, data: T): string;
17
+ write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): void;
18
+ getQuery<T extends Data>(ref: DataQuery<T>): Results<T>;
19
+ subscribeQuery<T extends Data>(ref: DataQuery<T>, observer: Observer<Results<T>>): Unsubscriber;
20
+ writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): void;
21
21
  /** Reset this provider and clear all data. */
22
22
  reset(): void;
23
23
  }
@@ -11,7 +11,7 @@ export class MemoryProvider extends Provider {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  /** List of tables in `{ path: Table }` format. */
14
- this._tables = {};
14
+ this._tables = {}; // eslint-disable-line @typescript-eslint/no-explicit-any
15
15
  }
16
16
  // Get a named collection (or create a new one).
17
17
  _table({ collection }) {