shelving 1.63.0 → 1.65.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.
Files changed (188) hide show
  1. package/api/Resource.js +2 -2
  2. package/db/Database.d.ts +2 -1
  3. package/db/Reference.d.ts +46 -39
  4. package/db/Reference.js +70 -73
  5. package/db/index.d.ts +0 -3
  6. package/db/index.js +0 -3
  7. package/error/ThroughError.d.ts +8 -0
  8. package/error/ThroughError.js +13 -0
  9. package/firestore/client/FirestoreClientProvider.d.ts +11 -11
  10. package/firestore/client/FirestoreClientProvider.js +21 -15
  11. package/firestore/lite/FirestoreLiteProvider.d.ts +10 -11
  12. package/firestore/lite/FirestoreLiteProvider.js +21 -16
  13. package/firestore/server/FirestoreServerProvider.d.ts +11 -11
  14. package/firestore/server/FirestoreServerProvider.js +23 -17
  15. package/index.d.ts +2 -1
  16. package/index.js +2 -1
  17. package/markup/rules.js +4 -4
  18. package/observe/AbstractObserver.d.ts +15 -0
  19. package/observe/AbstractObserver.js +42 -0
  20. package/observe/AsyncObserver.d.ts +5 -0
  21. package/observe/AsyncObserver.js +8 -0
  22. package/{stream/LastStream.d.ts → observe/LastSubject.d.ts} +2 -2
  23. package/observe/LastSubject.js +12 -0
  24. package/observe/MatchObserver.d.ts +9 -0
  25. package/observe/MatchObserver.js +12 -0
  26. package/observe/MatchableObserver.d.ts +7 -0
  27. package/observe/MatchableObserver.js +10 -0
  28. package/observe/Observable.d.ts +20 -0
  29. package/observe/Observable.js +7 -0
  30. package/observe/Observer.d.ts +31 -0
  31. package/observe/Observer.js +48 -0
  32. package/observe/OnceObserver.d.ts +5 -0
  33. package/observe/OnceObserver.js +8 -0
  34. package/observe/Subject.d.ts +46 -0
  35. package/observe/Subject.js +110 -0
  36. package/observe/ThroughObserver.d.ts +5 -0
  37. package/observe/ThroughObserver.js +8 -0
  38. package/observe/TransformObserver.d.ts +9 -0
  39. package/observe/TransformObserver.js +12 -0
  40. package/observe/TransformableObserver.d.ts +7 -0
  41. package/observe/TransformableObserver.js +8 -0
  42. package/observe/index.d.ts +13 -0
  43. package/observe/index.js +13 -0
  44. package/observe/util.d.ts +24 -0
  45. package/observe/util.js +34 -0
  46. package/package.json +3 -3
  47. package/provider/BatchProvider.d.ts +8 -8
  48. package/provider/BatchProvider.js +26 -31
  49. package/provider/CacheProvider.d.ts +12 -24
  50. package/provider/CacheProvider.js +40 -67
  51. package/provider/DebugProvider.d.ts +20 -0
  52. package/provider/DebugProvider.js +170 -0
  53. package/provider/MemoryProvider.d.ts +43 -14
  54. package/provider/MemoryProvider.js +148 -115
  55. package/provider/Provider.d.ts +23 -23
  56. package/provider/ThroughProvider.d.ts +20 -12
  57. package/provider/ThroughProvider.js +12 -12
  58. package/provider/ValidationProvider.d.ts +10 -10
  59. package/provider/ValidationProvider.js +69 -14
  60. package/provider/index.d.ts +1 -1
  61. package/provider/index.js +1 -1
  62. package/query/Filter.d.ts +8 -16
  63. package/query/Filter.js +8 -7
  64. package/query/Filters.d.ts +6 -11
  65. package/query/Filters.js +5 -5
  66. package/query/Query.d.ts +10 -13
  67. package/query/Query.js +10 -10
  68. package/query/Rule.d.ts +2 -3
  69. package/query/Sort.d.ts +7 -8
  70. package/query/Sort.js +5 -5
  71. package/query/Sorts.d.ts +3 -4
  72. package/query/Sorts.js +2 -2
  73. package/query/index.d.ts +0 -1
  74. package/query/index.js +0 -1
  75. package/react/index.d.ts +0 -6
  76. package/react/index.js +3 -6
  77. package/react/useDocument.d.ts +32 -39
  78. package/react/useDocument.js +71 -75
  79. package/react/useInstance.d.ts +4 -7
  80. package/react/useInstance.js +6 -9
  81. package/react/useLazy.d.ts +5 -9
  82. package/react/useQuery.d.ts +48 -46
  83. package/react/useQuery.js +116 -87
  84. package/react/useReduce.d.ts +8 -1
  85. package/react/useReduce.js +1 -3
  86. package/react/useSubscribe.d.ts +5 -6
  87. package/react/useSubscribe.js +10 -11
  88. package/schema/AllowSchema.d.ts +3 -4
  89. package/schema/AllowSchema.js +1 -1
  90. package/schema/MapSchema.js +2 -2
  91. package/schema/ObjectSchema.js +2 -2
  92. package/{stream → state}/ArrayState.d.ts +1 -1
  93. package/{stream → state}/ArrayState.js +8 -10
  94. package/{stream → state}/BooleanState.d.ts +1 -1
  95. package/{stream → state}/BooleanState.js +3 -5
  96. package/{stream → state}/DataState.d.ts +3 -3
  97. package/{stream → state}/DataState.js +6 -6
  98. package/{stream → state}/ObjectState.d.ts +1 -1
  99. package/{stream → state}/ObjectState.js +6 -8
  100. package/state/SelfClosingState.d.ts +18 -0
  101. package/state/SelfClosingState.js +34 -0
  102. package/state/State.d.ts +32 -0
  103. package/state/State.js +69 -0
  104. package/{stream → state}/index.d.ts +1 -4
  105. package/{stream → state}/index.js +1 -4
  106. package/test/basics.d.ts +12 -15
  107. package/test/basics.js +10 -20
  108. package/test/people.d.ts +9 -14
  109. package/test/people.js +6 -12
  110. package/test/util.d.ts +3 -3
  111. package/test/util.js +7 -7
  112. package/update/ArrayUpdate.d.ts +2 -1
  113. package/update/ArrayUpdate.js +4 -4
  114. package/update/DataUpdate.d.ts +2 -1
  115. package/update/DataUpdate.js +3 -2
  116. package/update/ObjectUpdate.d.ts +2 -1
  117. package/update/ObjectUpdate.js +14 -5
  118. package/update/Update.d.ts +2 -2
  119. package/update/util.d.ts +1 -4
  120. package/update/util.js +3 -3
  121. package/util/async.d.ts +4 -5
  122. package/util/async.js +3 -2
  123. package/util/clone.js +3 -3
  124. package/util/data.d.ts +42 -44
  125. package/util/data.js +32 -33
  126. package/util/entry.d.ts +15 -28
  127. package/util/entry.js +19 -13
  128. package/util/equal.d.ts +4 -5
  129. package/util/filter.d.ts +5 -46
  130. package/util/filter.js +5 -47
  131. package/util/function.d.ts +5 -5
  132. package/util/function.js +3 -3
  133. package/util/hydrate.d.ts +1 -1
  134. package/util/hydrate.js +7 -7
  135. package/util/index.d.ts +1 -1
  136. package/util/index.js +1 -1
  137. package/util/iterate.d.ts +15 -19
  138. package/util/iterate.js +7 -17
  139. package/util/match.d.ts +20 -0
  140. package/util/match.js +14 -0
  141. package/util/random.js +2 -3
  142. package/util/search.d.ts +1 -1
  143. package/util/sort.d.ts +4 -30
  144. package/util/sort.js +0 -38
  145. package/util/string.d.ts +1 -1
  146. package/util/string.js +2 -7
  147. package/util/template.js +2 -2
  148. package/util/timeout.d.ts +2 -0
  149. package/util/timeout.js +8 -1
  150. package/util/transform.d.ts +39 -44
  151. package/util/transform.js +21 -34
  152. package/util/validate.d.ts +26 -20
  153. package/util/validate.js +20 -22
  154. package/api/errors.d.ts +0 -8
  155. package/api/errors.js +0 -9
  156. package/db/PaginationState.d.ts +0 -31
  157. package/db/PaginationState.js +0 -67
  158. package/db/errors.d.ts +0 -25
  159. package/db/errors.js +0 -34
  160. package/db/util.d.ts +0 -37
  161. package/db/util.js +0 -54
  162. package/provider/ErrorProvider.d.ts +0 -32
  163. package/provider/ErrorProvider.js +0 -175
  164. package/query/util.d.ts +0 -8
  165. package/query/util.js +0 -8
  166. package/react/useCompare.d.ts +0 -3
  167. package/react/useCompare.js +0 -8
  168. package/react/useFetch.d.ts +0 -17
  169. package/react/useFetch.js +0 -41
  170. package/react/usePagination.d.ts +0 -8
  171. package/react/usePagination.js +0 -22
  172. package/react/usePureEffect.d.ts +0 -10
  173. package/react/usePureEffect.js +0 -17
  174. package/react/usePureState.d.ts +0 -11
  175. package/react/usePureState.js +0 -16
  176. package/react/useState.d.ts +0 -39
  177. package/react/useState.js +0 -65
  178. package/stream/LastStream.js +0 -12
  179. package/stream/LazyState.d.ts +0 -11
  180. package/stream/LazyState.js +0 -28
  181. package/stream/LazyStream.d.ts +0 -12
  182. package/stream/LazyStream.js +0 -28
  183. package/stream/State.d.ts +0 -46
  184. package/stream/State.js +0 -66
  185. package/stream/Stream.d.ts +0 -66
  186. package/stream/Stream.js +0 -122
  187. package/util/observe.d.ts +0 -111
  188. package/util/observe.js +0 -159
package/api/Resource.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { validate } from "../util/validate.js";
2
2
  import { getUndefined } from "../util/undefined.js";
3
3
  import { Feedback } from "../feedback/Feedback.js";
4
- import { ResourceValidationError } from "./errors.js";
4
+ import { ValidationError } from "../error/ValidationError.js";
5
5
  /**
6
6
  * An abstract API resource definition, used to specify types for e.g. serverless functions..
7
7
  *
@@ -34,7 +34,7 @@ export class Resource {
34
34
  return validate(unsafeResult, this.result);
35
35
  }
36
36
  catch (thrown) {
37
- throw thrown instanceof Feedback ? new ResourceValidationError(this, thrown) : thrown;
37
+ throw thrown instanceof Feedback ? new ValidationError(`Invalid result for resource`, thrown) : thrown;
38
38
  }
39
39
  }
40
40
  }
package/db/Database.d.ts CHANGED
@@ -3,6 +3,7 @@ import type { Key, Datas } from "../util/data.js";
3
3
  import type { Provider } from "../provider/Provider.js";
4
4
  import type { SortKeys } from "../query/Sort.js";
5
5
  import type { FilterProps } from "../query/Filter.js";
6
+ import { Entity } from "../util/data.js";
6
7
  import { DocumentReference, QueryReference } from "./Reference.js";
7
8
  /**
8
9
  * Combines a database model and a provider.
@@ -16,7 +17,7 @@ export declare class Database<V extends Validators<Datas> = Validators<Datas>> {
16
17
  readonly provider: Provider;
17
18
  constructor(validators: V, provider: Provider);
18
19
  /** Create a query on a collection in this model. */
19
- query<K extends Key<V>>(collection: K, filters?: FilterProps<ValidatorType<V[K]>>, sorts?: SortKeys<ValidatorType<V[K]>>, limit?: number | null): QueryReference<ValidatorType<V[K]>>;
20
+ query<K extends Key<V>>(collection: K, filters?: FilterProps<Entity<ValidatorType<V[K]>>>, sorts?: SortKeys<Entity<ValidatorType<V[K]>>>, limit?: number | null): QueryReference<ValidatorType<V[K]>>;
20
21
  /** Reference a document in a collection in this model. */
21
22
  doc<K extends Key<V>>(collection: K, id: string): DocumentReference<ValidatorType<V[K]>>;
22
23
  /**
package/db/Reference.d.ts CHANGED
@@ -1,15 +1,15 @@
1
- import type { Data, Result, Results } from "../util/data.js";
2
- import type { Dispatcher } from "../util/function.js";
1
+ import type { Data, OptionalData, Entity, OptionalEntity, Entities } from "../util/data.js";
2
+ import type { Dispatch } from "../util/function.js";
3
3
  import type { SortKeys } from "../query/Sort.js";
4
- import { Observable, Observer, Unsubscriber } from "../util/observe.js";
5
- import { Validatable, Validator } from "../util/validate.js";
4
+ import { ImmutableArray } from "../util/array.js";
5
+ import type { PartialObserver } from "../observe/Observer.js";
6
+ import type { Validator } from "../util/validate.js";
6
7
  import { Query } from "../query/Query.js";
7
- import { Entries, Entry } from "../util/entry.js";
8
8
  import { Filters } from "../query/Filters.js";
9
9
  import { Sorts } from "../query/Sorts.js";
10
10
  import { DataUpdate, PropUpdates } from "../update/DataUpdate.js";
11
11
  import { FilterProps } from "../query/Filter.js";
12
- import { DocumentData, DocumentResult } from "./util.js";
12
+ import { Observable, Unsubscribe } from "../observe/Observable.js";
13
13
  import type { Database } from "./Database.js";
14
14
  /** A refence to a location in a database. */
15
15
  export interface Reference {
@@ -17,11 +17,11 @@ export interface Reference {
17
17
  toString(): string;
18
18
  }
19
19
  /** A query reference within a specific database. */
20
- export declare class QueryReference<T extends Data = Data> extends Query<T> implements Observable<Results<T>>, Validatable<Entries<T>>, Iterable<Entry<T>>, Reference {
20
+ export declare class QueryReference<T extends Data = Data> extends Query<Entity<T>> implements Observable<ImmutableArray<Entity<T>>>, Reference {
21
21
  readonly db: Database;
22
22
  readonly validator: Validator<T>;
23
23
  readonly collection: string;
24
- constructor(db: Database, validator: Validator<T>, collection: string, filters?: Filters<T>, sorts?: Sorts<T>, limit?: number | null);
24
+ constructor(db: Database, validator: Validator<T>, collection: string, filters?: Filters<Entity<T>>, sorts?: Sorts<Entity<T>>, limit?: number | null);
25
25
  /** Reference a document in this query's collection. */
26
26
  doc(id: string): DocumentReference<T>;
27
27
  /**
@@ -33,15 +33,10 @@ export declare class QueryReference<T extends Data = Data> extends Query<T> impl
33
33
  */
34
34
  add(data: T): string | PromiseLike<string>;
35
35
  /**
36
- * Get an iterable that yields the results of this entry.
37
- * @return Map containing the results.
36
+ * Get array of entities for this query.
37
+ * @return Array of entities.
38
38
  */
39
- get entries(): Entries<T> | PromiseLike<Entries<T>>;
40
- /**
41
- * Get an iterable that yields the results of this entry.
42
- * @return Map containing the results.
43
- */
44
- get results(): Results<T> | PromiseLike<Results<T>>;
39
+ get value(): Entities<T> | PromiseLike<Entities<T>>;
45
40
  /**
46
41
  * Count the number of results of this set of documents.
47
42
  * @return Number of documents matching the query (possibly promised).
@@ -53,19 +48,25 @@ export declare class QueryReference<T extends Data = Data> extends Query<T> impl
53
48
  */
54
49
  get exists(): boolean | PromiseLike<boolean>;
55
50
  /**
56
- * Get an entry for the first document matched by this query or `undefined` if this query has no results.
57
- *
58
- * @return Entry in `[id, data]` format for the first document.
51
+ * Get the first document matched by this query or `null` if this query has no results.
59
52
  * @throws RequiredError if there were no results for this query.
60
53
  */
61
- get result(): DocumentResult<T> | PromiseLike<DocumentResult<T>>;
54
+ get firstValue(): OptionalEntity<T> | PromiseLike<OptionalEntity<T>>;
62
55
  /**
63
- * Get an entry for the first document matched by this query.
64
- *
65
- * @return Entry in `[id, data]` format for the first document.
56
+ * Get the first document matched by this query.
57
+ * @throws RequiredError if there were no results for this query.
58
+ */
59
+ get firstData(): Entity<T> | PromiseLike<Entity<T>>;
60
+ /**
61
+ * Get the last document matched by this query or `null` if this query has no results.
62
+ * @throws RequiredError if there were no results for this query.
63
+ */
64
+ get lastValue(): OptionalEntity<T> | PromiseLike<OptionalEntity<T>>;
65
+ /**
66
+ * Get the last document matched by this query.
66
67
  * @throws RequiredError if there were no results for this query.
67
68
  */
68
- get data(): DocumentData<T> | PromiseLike<DocumentData<T>>;
69
+ get lastData(): Entity<T> | PromiseLike<Entity<T>>;
69
70
  /**
70
71
  * Subscribe to all matching documents.
71
72
  * - `next()` is called once with the initial results, and again any time the results change.
@@ -73,7 +74,7 @@ export declare class QueryReference<T extends Data = Data> extends Query<T> impl
73
74
  * @param next Observer with `next`, `error`, or `complete` methods or a `next()` dispatcher.
74
75
  * @return Function that ends the subscription.
75
76
  */
76
- subscribe(next: Observer<Results<T>> | Dispatcher<[Results<T>]>): Unsubscriber;
77
+ subscribe(next: PartialObserver<ImmutableArray<Entity<T>>> | Dispatch<[ImmutableArray<Entity<T>>]>): Unsubscribe;
77
78
  /**
78
79
  * Set all matching documents to the same exact value.
79
80
  *
@@ -93,21 +94,17 @@ export declare class QueryReference<T extends Data = Data> extends Query<T> impl
93
94
  * @return Nothing (possibly promised).
94
95
  */
95
96
  delete(): number | PromiseLike<number>;
96
- /** Iterate over the resuls (will throw `Promise` if the results are asynchronous). */
97
- [Symbol.iterator](): Iterator<Entry<T>, void>;
98
- /** Validate a set of results for this query reference. */
99
- validate(unsafeEntries: Entries): Entries<T>;
100
97
  toString(): string;
101
98
  }
102
99
  /** A document reference within a specific database. */
103
- export declare class DocumentReference<T extends Data = Data> implements Observable<Result<T>>, Validatable<T>, Reference {
100
+ export declare class DocumentReference<T extends Data = Data> implements Observable<OptionalData<T>>, Reference {
104
101
  readonly db: Database;
105
102
  readonly validator: Validator<T>;
106
103
  readonly collection: string;
107
104
  readonly id: string;
108
105
  constructor(db: Database, validator: Validator<T>, collection: string, id: string);
109
106
  /** Create a query on this document's collection. */
110
- query(filters?: FilterProps<T>, sorts?: SortKeys<T>, limit?: number | null): QueryReference<T>;
107
+ query(filters?: FilterProps<Entity<T>>, sorts?: SortKeys<Entity<T>>, limit?: number | null): QueryReference<T>;
111
108
  /** Get an 'optional' reference to this document (uses a `ModelQuery` with an `id` filter). */
112
109
  get optional(): QueryReference<T>;
113
110
  /**
@@ -116,18 +113,18 @@ export declare class DocumentReference<T extends Data = Data> implements Observa
116
113
  */
117
114
  get exists(): boolean | PromiseLike<boolean>;
118
115
  /**
119
- * Get the result of this document.
120
- * @return Document's data, or `undefined` if the document doesn't exist (possibly promised).
116
+ * Get the optional data of this document.
117
+ * @return Document's data, or `null` if the document doesn't exist (possibly promised).
121
118
  */
122
- get result(): DocumentResult<T> | PromiseLike<DocumentResult<T>>;
119
+ get value(): OptionalEntity<T> | PromiseLike<OptionalEntity<T>>;
123
120
  /**
124
121
  * Get the data of this document.
125
122
  * - Useful for destructuring, e.g. `{ name, title } = await documentThatMustExist.asyncData`
126
123
  *
127
124
  * @return Document's data (possibly promised).
128
- * @throws RequiredError if the document's result was undefined.
125
+ * @throws RequiredError if the document does not exist.
129
126
  */
130
- get data(): DocumentData<T> | PromiseLike<DocumentData<T>>;
127
+ get data(): Entity<T> | PromiseLike<Entity<T>>;
131
128
  /**
132
129
  * Subscribe to the result of this document (indefinitely).
133
130
  * - `next()` is called once with the initial result, and again any time the result changes.
@@ -135,14 +132,24 @@ export declare class DocumentReference<T extends Data = Data> implements Observa
135
132
  * @param next Observer with `next`, `error`, or `complete` methods or a `next()` dispatcher.
136
133
  * @return Function that ends the subscription.
137
134
  */
138
- subscribe(next: Observer<DocumentResult<T>> | Dispatcher<[DocumentResult<T>]>): Unsubscriber;
135
+ subscribe(next: PartialObserver<OptionalEntity<T>> | Dispatch<[OptionalEntity<T>]>): Unsubscribe;
139
136
  /** Set the complete data of this document. */
140
137
  set(data: T): void | PromiseLike<void>;
141
138
  /** Update this document. */
142
139
  update(updates: DataUpdate<T> | PropUpdates<T>): void | PromiseLike<void>;
143
140
  /** Delete this document. */
144
141
  delete(): void | PromiseLike<void>;
145
- /** Validate data for this query reference. */
146
- validate(unsafeData: Data): T;
147
142
  toString(): string;
148
143
  }
144
+ /** Get the data for a document from a result for that document. */
145
+ export declare function getDocumentData<T extends Data>(entity: OptionalEntity<T>, ref: DocumentReference<T>): Entity<T>;
146
+ /** Get the data for a document from a set of queried entities. */
147
+ export declare function getQueryFirstData<T extends Data>(entities: Entities<T>, ref: QueryReference<T>): Entity<T>;
148
+ /** Get the data for a document from a set of queried entities. */
149
+ export declare function getQueryLastData<T extends Data>(entities: Entities<T>, ref: QueryReference<T>): Entity<T>;
150
+ /** Get the optional data for a document from a set of queried entities. */
151
+ export declare function getQueryFirstValue<T extends Data>(entities: Entities<T>): OptionalEntity<T>;
152
+ /** Get the optional data for a document from a set of queried entities. */
153
+ export declare function getQueryLastValue<T extends Data>(entities: Entities<T>): OptionalEntity<T>;
154
+ /** Are two database references equal? */
155
+ export declare const isSameReference: (left: Reference, right: Reference) => boolean;
package/db/Reference.js CHANGED
@@ -1,17 +1,12 @@
1
- import { ResultsObserver } from "../util/observe.js";
2
- import { validate } from "../util/validate.js";
1
+ import { getFirstItem, getLastItem } from "../util/array.js";
3
2
  import { Query } from "../query/Query.js";
4
3
  import { Filters } from "../query/Filters.js";
5
4
  import { Sorts } from "../query/Sorts.js";
6
- import { callAsync, throwAsync } from "../util/async.js";
7
- import { getMap } from "../util/map.js";
5
+ import { callAsync } from "../util/async.js";
8
6
  import { countItems, hasItems } from "../util/iterate.js";
9
7
  import { DataUpdate } from "../update/DataUpdate.js";
10
- import { Feedback } from "../feedback/Feedback.js";
11
- import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
12
8
  import { Filter } from "../query/Filter.js";
13
- import { DocumentValidationError, QueryValidationError } from "./errors.js";
14
- import { DocumentResultObserver, getDocumentData, getDocumentResult, getQueryData, getQueryResult } from "./util.js";
9
+ import { RequiredError } from "../error/RequiredError.js";
15
10
  /** A query reference within a specific database. */
16
11
  export class QueryReference extends Query {
17
12
  constructor(db, validator, collection, filters, sorts, limit) {
@@ -32,28 +27,21 @@ export class QueryReference extends Query {
32
27
  * @return String ID for the created document (possibly promised).
33
28
  */
34
29
  add(data) {
35
- return this.db.provider.add(this, data);
30
+ return this.db.provider.addDocument(this, data);
36
31
  }
37
32
  /**
38
- * Get an iterable that yields the results of this entry.
39
- * @return Map containing the results.
33
+ * Get array of entities for this query.
34
+ * @return Array of entities.
40
35
  */
41
- get entries() {
36
+ get value() {
42
37
  return this.db.provider.getQuery(this);
43
38
  }
44
- /**
45
- * Get an iterable that yields the results of this entry.
46
- * @return Map containing the results.
47
- */
48
- get results() {
49
- return callAsync(getMap, this.db.provider.getQuery(this));
50
- }
51
39
  /**
52
40
  * Count the number of results of this set of documents.
53
41
  * @return Number of documents matching the query (possibly promised).
54
42
  */
55
43
  get count() {
56
- return callAsync(countItems, this.entries);
44
+ return callAsync(countItems, this.value);
57
45
  }
58
46
  /**
59
47
  * Does at least one document exist for this query?
@@ -63,22 +51,32 @@ export class QueryReference extends Query {
63
51
  return callAsync(hasItems, this.db.provider.getQuery(this.max(1)));
64
52
  }
65
53
  /**
66
- * Get an entry for the first document matched by this query or `undefined` if this query has no results.
67
- *
68
- * @return Entry in `[id, data]` format for the first document.
54
+ * Get the first document matched by this query or `null` if this query has no results.
69
55
  * @throws RequiredError if there were no results for this query.
70
56
  */
71
- get result() {
72
- return callAsync(getQueryResult, this.db.provider.getQuery(this.max(1)), this);
57
+ get firstValue() {
58
+ return callAsync(getQueryFirstValue, this.db.provider.getQuery(this.max(1)));
73
59
  }
74
60
  /**
75
- * Get an entry for the first document matched by this query.
76
- *
77
- * @return Entry in `[id, data]` format for the first document.
61
+ * Get the first document matched by this query.
78
62
  * @throws RequiredError if there were no results for this query.
79
63
  */
80
- get data() {
81
- return callAsync(getQueryData, this.db.provider.getQuery(this.max(1)), this);
64
+ get firstData() {
65
+ return callAsync(getQueryFirstData, this.db.provider.getQuery(this.max(1)), this);
66
+ }
67
+ /**
68
+ * Get the last document matched by this query or `null` if this query has no results.
69
+ * @throws RequiredError if there were no results for this query.
70
+ */
71
+ get lastValue() {
72
+ return callAsync(getQueryLastValue, this.db.provider.getQuery(this.max(1)));
73
+ }
74
+ /**
75
+ * Get the last document matched by this query.
76
+ * @throws RequiredError if there were no results for this query.
77
+ */
78
+ get lastData() {
79
+ return callAsync(getQueryLastData, this.db.provider.getQuery(this.max(1)), this);
82
80
  }
83
81
  /**
84
82
  * Subscribe to all matching documents.
@@ -88,7 +86,7 @@ export class QueryReference extends Query {
88
86
  * @return Function that ends the subscription.
89
87
  */
90
88
  subscribe(next) {
91
- return this.db.provider.subscribeQuery(this, new ResultsObserver(typeof next === "function" ? { next } : next));
89
+ return this.db.provider.subscribeQuery(this, typeof next === "function" ? { next } : next);
92
90
  }
93
91
  /**
94
92
  * Set all matching documents to the same exact value.
@@ -115,28 +113,6 @@ export class QueryReference extends Query {
115
113
  delete() {
116
114
  return this.db.provider.deleteQuery(this);
117
115
  }
118
- /** Iterate over the resuls (will throw `Promise` if the results are asynchronous). */
119
- [Symbol.iterator]() {
120
- return throwAsync(this.entries)[Symbol.iterator]();
121
- }
122
- /** Validate a set of results for this query reference. */
123
- *validate(unsafeEntries) {
124
- let invalid = false;
125
- const details = {};
126
- for (const [id, unsafeValue] of unsafeEntries) {
127
- try {
128
- yield [id, validate(unsafeValue, this.validator)];
129
- }
130
- catch (thrown) {
131
- if (!(thrown instanceof Feedback))
132
- throw thrown;
133
- invalid = true;
134
- details[id] = thrown;
135
- }
136
- }
137
- if (invalid)
138
- throw new QueryValidationError(this, new InvalidFeedback("Invalid results", details));
139
- }
140
116
  // Override to include the collection name.
141
117
  toString() {
142
118
  return `${this.collection}?${super.toString()}`;
@@ -163,24 +139,24 @@ export class DocumentReference {
163
139
  * @return `true` if a document exists or `false` otherwise (possibly promised).
164
140
  */
165
141
  get exists() {
166
- return callAsync(Boolean, this.db.provider.get(this));
142
+ return callAsync(Boolean, this.db.provider.getDocument(this));
167
143
  }
168
144
  /**
169
- * Get the result of this document.
170
- * @return Document's data, or `undefined` if the document doesn't exist (possibly promised).
145
+ * Get the optional data of this document.
146
+ * @return Document's data, or `null` if the document doesn't exist (possibly promised).
171
147
  */
172
- get result() {
173
- return callAsync(getDocumentResult, this.db.provider.get(this), this);
148
+ get value() {
149
+ return this.db.provider.getDocument(this);
174
150
  }
175
151
  /**
176
152
  * Get the data of this document.
177
153
  * - Useful for destructuring, e.g. `{ name, title } = await documentThatMustExist.asyncData`
178
154
  *
179
155
  * @return Document's data (possibly promised).
180
- * @throws RequiredError if the document's result was undefined.
156
+ * @throws RequiredError if the document does not exist.
181
157
  */
182
158
  get data() {
183
- return callAsync(getDocumentData, this.db.provider.get(this), this);
159
+ return callAsync(getDocumentData, this.db.provider.getDocument(this), this);
184
160
  }
185
161
  /**
186
162
  * Subscribe to the result of this document (indefinitely).
@@ -190,31 +166,52 @@ export class DocumentReference {
190
166
  * @return Function that ends the subscription.
191
167
  */
192
168
  subscribe(next) {
193
- return this.db.provider.subscribe(this, new DocumentResultObserver(typeof next === "function" ? { next } : next, this));
169
+ return this.db.provider.subscribeDocument(this, typeof next === "function" ? { next } : next);
194
170
  }
195
171
  /** Set the complete data of this document. */
196
172
  set(data) {
197
- return this.db.provider.set(this, data);
173
+ return this.db.provider.setDocument(this, data);
198
174
  }
199
175
  /** Update this document. */
200
176
  update(updates) {
201
- return this.db.provider.update(this, updates instanceof DataUpdate ? updates : new DataUpdate(updates));
177
+ return this.db.provider.updateDocument(this, updates instanceof DataUpdate ? updates : new DataUpdate(updates));
202
178
  }
203
179
  /** Delete this document. */
204
180
  delete() {
205
- return this.db.provider.delete(this);
206
- }
207
- /** Validate data for this query reference. */
208
- validate(unsafeData) {
209
- try {
210
- return validate(unsafeData, this.validator);
211
- }
212
- catch (thrown) {
213
- throw thrown instanceof Feedback ? new DocumentValidationError(this, thrown) : thrown;
214
- }
181
+ return this.db.provider.deleteDocument(this);
215
182
  }
216
183
  // Implement toString()
217
184
  toString() {
218
185
  return `${this.collection}/${this.id}`;
219
186
  }
220
187
  }
188
+ /** Get the data for a document from a result for that document. */
189
+ export function getDocumentData(entity, ref) {
190
+ if (entity)
191
+ return entity;
192
+ throw new RequiredError(`Document "${ref}" does not exist`);
193
+ }
194
+ /** Get the data for a document from a set of queried entities. */
195
+ export function getQueryFirstData(entities, ref) {
196
+ const entity = getQueryFirstValue(entities);
197
+ if (entity)
198
+ return entity;
199
+ throw new RequiredError(`Query "${ref}" has no documents`);
200
+ }
201
+ /** Get the data for a document from a set of queried entities. */
202
+ export function getQueryLastData(entities, ref) {
203
+ const entity = getQueryLastValue(entities);
204
+ if (entity)
205
+ return entity;
206
+ throw new RequiredError(`Query "${ref}" has no documents`);
207
+ }
208
+ /** Get the optional data for a document from a set of queried entities. */
209
+ export function getQueryFirstValue(entities) {
210
+ return getFirstItem(entities) || null;
211
+ }
212
+ /** Get the optional data for a document from a set of queried entities. */
213
+ export function getQueryLastValue(entities) {
214
+ return getLastItem(entities) || null;
215
+ }
216
+ /** Are two database references equal? */
217
+ export const isSameReference = (left, right) => left === right || left.toString() === right.toString();
package/db/index.d.ts CHANGED
@@ -1,6 +1,3 @@
1
1
  export * from "./Database.js";
2
2
  export * from "./Reference.js";
3
3
  export * from "./Operation.js";
4
- export * from "./PaginationState.js";
5
- export * from "./util.js";
6
- export * from "./errors.js";
package/db/index.js CHANGED
@@ -1,6 +1,3 @@
1
1
  export * from "./Database.js";
2
2
  export * from "./Reference.js";
3
3
  export * from "./Operation.js";
4
- export * from "./PaginationState.js";
5
- export * from "./util.js";
6
- export * from "./errors.js";
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Thrown to wrap an error with another error.
3
+ * - Merges the message and stack of the previous message.
4
+ */
5
+ export declare class ThroughError extends Error {
6
+ readonly cause: Error | unknown;
7
+ constructor(message: string, cause: Error | unknown);
8
+ }
@@ -0,0 +1,13 @@
1
+ import { debug } from "../util/debug.js";
2
+ /**
3
+ * Thrown to wrap an error with another error.
4
+ * - Merges the message and stack of the previous message.
5
+ */
6
+ export class ThroughError extends Error {
7
+ constructor(message, cause) {
8
+ super(message);
9
+ this.cause = cause;
10
+ this.stack = `${this.stack}\nCause: ${cause instanceof Error ? cause.stack : debug(cause)}`;
11
+ }
12
+ }
13
+ ThroughError.prototype.name = "ThroughError";
@@ -1,10 +1,10 @@
1
1
  import type { Firestore } from "firebase/firestore";
2
2
  import type { DocumentReference, QueryReference } from "../../db/Reference.js";
3
- import type { Data, Result } from "../../util/data.js";
4
- import type { Entries } from "../../util/entry.js";
3
+ import type { Data, Entities, OptionalEntity } from "../../util/data.js";
4
+ import type { Unsubscribe } from "../../observe/Observable.js";
5
5
  import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
6
6
  import { DataUpdate } from "../../update/DataUpdate.js";
7
- import { Observer, Unsubscriber } from "../../util/observe.js";
7
+ import { Observer } from "../../observe/Observer.js";
8
8
  /**
9
9
  * Firestore client database provider.
10
10
  * - Works with the Firebase JS SDK.
@@ -14,14 +14,14 @@ import { Observer, Unsubscriber } from "../../util/observe.js";
14
14
  export declare class FirestoreClientProvider extends Provider implements AsynchronousProvider {
15
15
  readonly firestore: Firestore;
16
16
  constructor(firestore: Firestore);
17
- get<T extends Data>(ref: DocumentReference<T>): Promise<Result<T>>;
18
- subscribe<T extends Data>(ref: DocumentReference<T>, observer: Observer<Result<T>>): Unsubscriber;
19
- add<T extends Data>(ref: QueryReference<T>, data: T): Promise<string>;
20
- set<T extends Data>(ref: DocumentReference<T>, data: T): Promise<void>;
21
- update<T extends Data>(ref: DocumentReference<T>, update: DataUpdate<T>): Promise<void>;
22
- delete<T extends Data>(ref: DocumentReference<T>): Promise<void>;
23
- getQuery<T extends Data>(ref: QueryReference<T>): Promise<Entries<T>>;
24
- subscribeQuery<T extends Data>(ref: QueryReference<T>, observer: Observer<Entries<T>>): Unsubscriber;
17
+ getDocument<T extends Data>(ref: DocumentReference<T>): Promise<OptionalEntity<T>>;
18
+ subscribeDocument<T extends Data>(ref: DocumentReference<T>, observer: Observer<OptionalEntity<T>>): Unsubscribe;
19
+ addDocument<T extends Data>(ref: QueryReference<T>, data: T): Promise<string>;
20
+ setDocument<T extends Data>(ref: DocumentReference<T>, data: T): Promise<void>;
21
+ updateDocument<T extends Data>(ref: DocumentReference<T>, update: DataUpdate<T>): Promise<void>;
22
+ deleteDocument<T extends Data>(ref: DocumentReference<T>): Promise<void>;
23
+ getQuery<T extends Data>(ref: QueryReference<T>): Promise<Entities<T>>;
24
+ subscribeQuery<T extends Data>(ref: QueryReference<T>, observer: Observer<Entities<T>>): Unsubscribe;
25
25
  setQuery<T extends Data>(ref: QueryReference<T>, data: T): Promise<number>;
26
26
  updateQuery<T extends Data>(ref: QueryReference<T>, update: DataUpdate<T>): Promise<number>;
27
27
  deleteQuery<T extends Data>(ref: QueryReference<T>): Promise<number>;
@@ -5,7 +5,7 @@ import { ArrayUpdate } from "../../update/ArrayUpdate.js";
5
5
  import { DataUpdate } from "../../update/DataUpdate.js";
6
6
  import { Increment } from "../../update/Increment.js";
7
7
  import { ObjectUpdate } from "../../update/ObjectUpdate.js";
8
- import { dispatchError, dispatchNext } from "../../util/observe.js";
8
+ import { dispatchError, dispatchNext } from "../../observe/Observer.js";
9
9
  // Constants.
10
10
  // const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
11
11
  const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
@@ -46,10 +46,16 @@ function getQuery(firestore, ref) {
46
46
  constraints.push(firestoreLimit(limit));
47
47
  return firestoreQuery(getCollection(firestore, ref), ...constraints);
48
48
  }
49
- /** Create a set of results from a collection snapshot. */
50
- function* getResults(snapshot) {
51
- for (const s of snapshot.docs)
52
- yield [s.id, s.data()];
49
+ function getEntities(snapshot) {
50
+ return snapshot.docs.map(getEntity);
51
+ }
52
+ function getEntity(snapshot) {
53
+ const data = snapshot.data();
54
+ return { ...data, id: snapshot.id };
55
+ }
56
+ function getOptionalEntity(snapshot) {
57
+ const data = snapshot.data();
58
+ return data ? { ...data, id: snapshot.id } : null;
53
59
  }
54
60
  /** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
55
61
  function* yieldFieldValues(updates, prefix = "") {
@@ -83,31 +89,31 @@ export class FirestoreClientProvider extends Provider {
83
89
  super();
84
90
  this.firestore = firestore;
85
91
  }
86
- async get(ref) {
87
- return (await getDoc(getDocument(this.firestore, ref))).data() || null;
92
+ async getDocument(ref) {
93
+ return getOptionalEntity(await getDoc(getDocument(this.firestore, ref)));
88
94
  }
89
- subscribe(ref, observer) {
90
- return onSnapshot(getDocument(this.firestore, ref), snapshot => dispatchNext(observer, snapshot.data() || null), thrown => dispatchError(observer, thrown));
95
+ subscribeDocument(ref, observer) {
96
+ return onSnapshot(getDocument(this.firestore, ref), snapshot => dispatchNext(observer, getOptionalEntity(snapshot)), thrown => dispatchError(observer, thrown));
91
97
  }
92
- async add(ref, data) {
98
+ async addDocument(ref, data) {
93
99
  const reference = await addDoc(getCollection(this.firestore, ref), data);
94
100
  return reference.id;
95
101
  }
96
- async set(ref, data) {
102
+ async setDocument(ref, data) {
97
103
  await setDoc(getDocument(this.firestore, ref), data);
98
104
  }
99
- async update(ref, update) {
105
+ async updateDocument(ref, update) {
100
106
  const fieldValues = Object.fromEntries(yieldFieldValues(update));
101
107
  await updateDoc(getDocument(this.firestore, ref), fieldValues);
102
108
  }
103
- async delete(ref) {
109
+ async deleteDocument(ref) {
104
110
  await deleteDoc(getDocument(this.firestore, ref));
105
111
  }
106
112
  async getQuery(ref) {
107
- return getResults(await getDocs(getQuery(this.firestore, ref)));
113
+ return getEntities(await getDocs(getQuery(this.firestore, ref)));
108
114
  }
109
115
  subscribeQuery(ref, observer) {
110
- return onSnapshot(getQuery(this.firestore, ref), snapshot => dispatchNext(observer, getResults(snapshot)), thrown => dispatchError(observer, thrown));
116
+ return onSnapshot(getQuery(this.firestore, ref), snapshot => dispatchNext(observer, getEntities(snapshot)), thrown => dispatchError(observer, thrown));
111
117
  }
112
118
  async setQuery(ref, data) {
113
119
  const snapshot = await getDocs(getQuery(this.firestore, ref));
@@ -1,8 +1,7 @@
1
1
  import type { Firestore } from "firebase/firestore/lite";
2
2
  import type { DocumentReference, QueryReference } from "../../db/Reference.js";
3
- import type { Data, Result } from "../../util/data.js";
4
- import type { Entries } from "../../util/entry.js";
5
- import type { Unsubscriber } from "../../util/observe.js";
3
+ import type { Data, Entities, OptionalEntity } from "../../util/data.js";
4
+ import type { Unsubscribe } from "../../observe/Observable.js";
6
5
  import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
7
6
  import { DataUpdate } from "../../update/DataUpdate.js";
8
7
  /**
@@ -14,14 +13,14 @@ import { DataUpdate } from "../../update/DataUpdate.js";
14
13
  export declare class FirestoreClientProvider extends Provider implements AsynchronousProvider {
15
14
  readonly firestore: Firestore;
16
15
  constructor(firestore: Firestore);
17
- get<T extends Data>(ref: DocumentReference<T>): Promise<Result<T>>;
18
- subscribe(): Unsubscriber;
19
- add<T extends Data>(ref: QueryReference<T>, data: T): Promise<string>;
20
- set<T extends Data>(ref: DocumentReference<T>, data: T): Promise<void>;
21
- update<T extends Data>(ref: DocumentReference<T>, update: DataUpdate<T>): Promise<void>;
22
- delete<T extends Data>(ref: DocumentReference<T>): Promise<void>;
23
- getQuery<T extends Data>(ref: QueryReference<T>): Promise<Entries<T>>;
24
- subscribeQuery(): Unsubscriber;
16
+ getDocument<T extends Data>(ref: DocumentReference<T>): Promise<OptionalEntity<T>>;
17
+ subscribeDocument(): Unsubscribe;
18
+ addDocument<T extends Data>(ref: QueryReference<T>, data: T): Promise<string>;
19
+ setDocument<T extends Data>(ref: DocumentReference<T>, data: T): Promise<void>;
20
+ updateDocument<T extends Data>(ref: DocumentReference<T>, update: DataUpdate<T>): Promise<void>;
21
+ deleteDocument<T extends Data>(ref: DocumentReference<T>): Promise<void>;
22
+ getQuery<T extends Data>(ref: QueryReference<T>): Promise<Entities<T>>;
23
+ subscribeQuery(): Unsubscribe;
25
24
  setQuery<T extends Data>(ref: QueryReference<T>, data: T): Promise<number>;
26
25
  updateQuery<T extends Data>(ref: QueryReference<T>, update: DataUpdate<T>): Promise<number>;
27
26
  deleteQuery<T extends Data>(ref: QueryReference<T>): Promise<number>;