shelving 1.62.1 → 1.64.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/db/Database.d.ts +2 -1
- package/db/PaginationState.d.ts +4 -7
- package/db/PaginationState.js +7 -15
- package/db/Reference.d.ts +22 -29
- package/db/Reference.js +19 -54
- package/db/errors.d.ts +0 -12
- package/db/errors.js +0 -17
- package/db/util.d.ts +4 -30
- package/db/util.js +7 -40
- package/firestore/client/FirestoreClientProvider.d.ts +5 -6
- package/firestore/client/FirestoreClientProvider.js +8 -3
- package/firestore/lite/FirestoreLiteProvider.d.ts +3 -4
- package/firestore/lite/FirestoreLiteProvider.js +10 -6
- package/firestore/server/FirestoreServerProvider.d.ts +5 -6
- package/firestore/server/FirestoreServerProvider.js +10 -5
- package/package.json +3 -3
- package/provider/BatchProvider.d.ts +7 -7
- package/provider/BatchProvider.js +8 -8
- package/provider/CacheProvider.d.ts +6 -9
- package/provider/CacheProvider.js +24 -17
- package/provider/ErrorProvider.d.ts +5 -6
- package/provider/MemoryProvider.d.ts +25 -10
- package/provider/MemoryProvider.js +57 -63
- package/provider/Provider.d.ts +9 -10
- package/provider/ThroughProvider.d.ts +5 -6
- package/provider/ValidationProvider.d.ts +4 -5
- package/provider/ValidationProvider.js +58 -6
- package/query/Filter.d.ts +7 -15
- package/query/Filter.js +6 -6
- package/query/Filters.d.ts +5 -10
- package/query/Filters.js +5 -5
- package/query/Query.d.ts +10 -13
- package/query/Query.js +10 -10
- package/query/Rule.d.ts +2 -3
- package/query/Sort.d.ts +7 -8
- package/query/Sort.js +5 -5
- package/query/Sorts.d.ts +3 -4
- package/query/Sorts.js +2 -2
- package/query/index.d.ts +0 -1
- package/query/index.js +0 -1
- package/react/useDocument.d.ts +10 -10
- package/react/useDocument.js +5 -4
- package/react/usePagination.d.ts +2 -2
- package/react/usePagination.js +5 -2
- package/react/useQuery.d.ts +14 -14
- package/react/useQuery.js +8 -8
- package/schema/AllowSchema.d.ts +3 -4
- package/schema/AllowSchema.js +1 -1
- package/schema/MapSchema.js +2 -2
- package/schema/ObjectSchema.js +2 -2
- package/test/basics.d.ts +12 -15
- package/test/basics.js +10 -20
- package/test/people.d.ts +9 -14
- package/test/people.js +6 -12
- package/test/util.d.ts +3 -3
- package/test/util.js +7 -7
- package/update/ArrayUpdate.d.ts +2 -1
- package/update/ArrayUpdate.js +4 -4
- package/update/DataUpdate.d.ts +2 -1
- package/update/DataUpdate.js +3 -2
- package/update/ObjectUpdate.d.ts +2 -1
- package/update/ObjectUpdate.js +14 -5
- package/update/Update.d.ts +2 -2
- package/update/util.d.ts +1 -4
- package/update/util.js +3 -3
- package/util/array.d.ts +8 -0
- package/util/array.js +4 -0
- package/util/clone.js +4 -5
- package/util/data.d.ts +35 -41
- package/util/data.js +33 -34
- package/util/entry.d.ts +14 -25
- package/util/entry.js +19 -13
- package/util/filter.d.ts +5 -21
- package/util/filter.js +5 -23
- package/util/hydrate.d.ts +1 -1
- package/util/hydrate.js +8 -8
- package/util/iterate.d.ts +19 -17
- package/util/iterate.js +5 -11
- package/util/number.d.ts +4 -0
- package/util/number.js +7 -0
- package/util/object.d.ts +19 -0
- package/util/object.js +8 -0
- package/util/observe.d.ts +4 -12
- package/util/observe.js +3 -15
- package/util/random.js +2 -3
- package/util/sort.d.ts +0 -20
- package/util/sort.js +0 -27
- package/util/string.d.ts +1 -1
- package/util/string.js +2 -7
- package/util/template.js +2 -2
- package/util/transform.d.ts +7 -44
- package/util/transform.js +9 -36
- package/util/validate.d.ts +20 -10
- package/util/validate.js +19 -19
- package/query/util.d.ts +0 -8
- package/query/util.js +0 -8
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]
|
|
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/PaginationState.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { Data, Results } from "../util/data.js";
|
|
1
|
+
import type { Data, Entity } from "../util/data.js";
|
|
3
2
|
import { BooleanState } from "../stream/BooleanState.js";
|
|
4
|
-
import {
|
|
3
|
+
import { ArrayState } from "../stream/ArrayState.js";
|
|
5
4
|
import { QueryReference } from "./Reference.js";
|
|
6
5
|
/**
|
|
7
6
|
* State that wraps a `Documents` reference to enable pagination.
|
|
8
7
|
* - If you pass in initial values, it will use that as the first page.
|
|
9
8
|
* - If you don't pass in initial values, it will autoload the first page.
|
|
10
9
|
*/
|
|
11
|
-
export declare class PaginationState<T extends Data> extends
|
|
10
|
+
export declare class PaginationState<T extends Data> extends ArrayState<Entity<T>> {
|
|
12
11
|
/** Whether this pagination is currently loading results. */
|
|
13
12
|
readonly busy: BooleanState;
|
|
14
13
|
/** Reference to the query this pagination is paginating. */
|
|
@@ -25,7 +24,5 @@ export declare class PaginationState<T extends Data> extends State<Results<T>> i
|
|
|
25
24
|
* Merge more results into this pagination.
|
|
26
25
|
* @return The change in the number of results.
|
|
27
26
|
*/
|
|
28
|
-
merge(more:
|
|
29
|
-
/** Iterate over the entries of the values currently in the pagination. */
|
|
30
|
-
[Symbol.iterator](): Iterator<Entry<T>>;
|
|
27
|
+
merge(more: Iterable<Entity<T>>): void;
|
|
31
28
|
}
|
package/db/PaginationState.js
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import { ConditionError } from "../error/ConditionError.js";
|
|
2
2
|
import { BooleanState } from "../stream/BooleanState.js";
|
|
3
|
-
import { State } from "../stream/State.js";
|
|
4
3
|
import { getLastItem } from "../util/array.js";
|
|
5
|
-
import { NOVALUE } from "../util/constants.js";
|
|
6
|
-
import { yieldMerged } from "../util/iterate.js";
|
|
7
|
-
import { getMap } from "../util/map.js";
|
|
8
4
|
import { assertMax, assertNumber } from "../util/number.js";
|
|
5
|
+
import { ArrayState } from "../stream/ArrayState.js";
|
|
9
6
|
/**
|
|
10
7
|
* State that wraps a `Documents` reference to enable pagination.
|
|
11
8
|
* - If you pass in initial values, it will use that as the first page.
|
|
12
9
|
* - If you don't pass in initial values, it will autoload the first page.
|
|
13
10
|
*/
|
|
14
|
-
export class PaginationState extends
|
|
11
|
+
export class PaginationState extends ArrayState {
|
|
15
12
|
constructor(ref) {
|
|
16
13
|
super();
|
|
17
14
|
/** Whether this pagination is currently loading results. */
|
|
@@ -27,10 +24,9 @@ export class PaginationState extends State {
|
|
|
27
24
|
this.busy.next(true);
|
|
28
25
|
if (!this.exists) {
|
|
29
26
|
// First set of results.
|
|
30
|
-
this.
|
|
31
|
-
const next = await this.ref.results;
|
|
27
|
+
const next = await this.ref.array;
|
|
32
28
|
this.next(next);
|
|
33
|
-
if (next.
|
|
29
|
+
if (next.length < this.limit)
|
|
34
30
|
this.complete();
|
|
35
31
|
this.busy.next(false);
|
|
36
32
|
}
|
|
@@ -38,9 +34,9 @@ export class PaginationState extends State {
|
|
|
38
34
|
// Additional set of results.
|
|
39
35
|
const lastItem = getLastItem(this.value);
|
|
40
36
|
if (lastItem) {
|
|
41
|
-
const next = await this.ref.after(lastItem
|
|
37
|
+
const next = await this.ref.after(lastItem).array;
|
|
42
38
|
this.merge(next);
|
|
43
|
-
if (next.
|
|
39
|
+
if (next.length < this.limit)
|
|
44
40
|
this.complete();
|
|
45
41
|
this.busy.next(false);
|
|
46
42
|
return;
|
|
@@ -58,10 +54,6 @@ export class PaginationState extends State {
|
|
|
58
54
|
* @return The change in the number of results.
|
|
59
55
|
*/
|
|
60
56
|
merge(more) {
|
|
61
|
-
this.next(this.exists ?
|
|
62
|
-
}
|
|
63
|
-
/** Iterate over the entries of the values currently in the pagination. */
|
|
64
|
-
[Symbol.iterator]() {
|
|
65
|
-
return this.value[Symbol.iterator]();
|
|
57
|
+
this.next(this.exists ? [...this.value, ...more] : [...more]);
|
|
66
58
|
}
|
|
67
59
|
}
|
package/db/Reference.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import type { Data, Result,
|
|
1
|
+
import type { Data, Result, Entity } from "../util/data.js";
|
|
2
2
|
import type { Dispatcher } from "../util/function.js";
|
|
3
3
|
import type { SortKeys } from "../query/Sort.js";
|
|
4
|
+
import { ImmutableArray } from "../util/array.js";
|
|
4
5
|
import { Observable, Observer, Unsubscriber } from "../util/observe.js";
|
|
5
|
-
import {
|
|
6
|
+
import { 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";
|
|
13
12
|
import type { Database } from "./Database.js";
|
|
14
13
|
/** A refence to a location in a database. */
|
|
15
14
|
export interface Reference {
|
|
@@ -17,11 +16,11 @@ export interface Reference {
|
|
|
17
16
|
toString(): string;
|
|
18
17
|
}
|
|
19
18
|
/** A query reference within a specific database. */
|
|
20
|
-
export declare class QueryReference<T extends Data = Data> extends Query<T
|
|
19
|
+
export declare class QueryReference<T extends Data = Data> extends Query<Entity<T>> implements Observable<ImmutableArray<Entity<T>>>, Reference {
|
|
21
20
|
readonly db: Database;
|
|
22
21
|
readonly validator: Validator<T>;
|
|
23
22
|
readonly collection: string;
|
|
24
|
-
constructor(db: Database, validator: Validator<T>, collection: string, filters?: Filters<T
|
|
23
|
+
constructor(db: Database, validator: Validator<T>, collection: string, filters?: Filters<Entity<T>>, sorts?: Sorts<Entity<T>>, limit?: number | null);
|
|
25
24
|
/** Reference a document in this query's collection. */
|
|
26
25
|
doc(id: string): DocumentReference<T>;
|
|
27
26
|
/**
|
|
@@ -33,15 +32,15 @@ export declare class QueryReference<T extends Data = Data> extends Query<T> impl
|
|
|
33
32
|
*/
|
|
34
33
|
add(data: T): string | PromiseLike<string>;
|
|
35
34
|
/**
|
|
36
|
-
* Get an iterable that yields the
|
|
35
|
+
* Get an iterable that yields the entities of this query.
|
|
37
36
|
* @return Map containing the results.
|
|
38
37
|
*/
|
|
39
|
-
get
|
|
38
|
+
get items(): Iterable<Entity<T>> | PromiseLike<Iterable<Entity<T>>>;
|
|
40
39
|
/**
|
|
41
|
-
* Get an
|
|
42
|
-
* @return
|
|
40
|
+
* Get an array of the results of this .
|
|
41
|
+
* @return Array containing the entities.
|
|
43
42
|
*/
|
|
44
|
-
get
|
|
43
|
+
get array(): ImmutableArray<Entity<T>> | PromiseLike<ImmutableArray<Entity<T>>>;
|
|
45
44
|
/**
|
|
46
45
|
* Count the number of results of this set of documents.
|
|
47
46
|
* @return Number of documents matching the query (possibly promised).
|
|
@@ -53,19 +52,19 @@ export declare class QueryReference<T extends Data = Data> extends Query<T> impl
|
|
|
53
52
|
*/
|
|
54
53
|
get exists(): boolean | PromiseLike<boolean>;
|
|
55
54
|
/**
|
|
56
|
-
* Get
|
|
55
|
+
* Get the first document matched by this query or `null` if this query has no results.
|
|
57
56
|
*
|
|
58
57
|
* @return Entry in `[id, data]` format for the first document.
|
|
59
58
|
* @throws RequiredError if there were no results for this query.
|
|
60
59
|
*/
|
|
61
|
-
get result():
|
|
60
|
+
get result(): Result<Entity<T>> | PromiseLike<Result<Entity<T>>>;
|
|
62
61
|
/**
|
|
63
|
-
* Get
|
|
62
|
+
* Get the first document matched by this query.
|
|
64
63
|
*
|
|
65
64
|
* @return Entry in `[id, data]` format for the first document.
|
|
66
65
|
* @throws RequiredError if there were no results for this query.
|
|
67
66
|
*/
|
|
68
|
-
get data():
|
|
67
|
+
get data(): Entity<T> | PromiseLike<Entity<T>>;
|
|
69
68
|
/**
|
|
70
69
|
* Subscribe to all matching documents.
|
|
71
70
|
* - `next()` is called once with the initial results, and again any time the results change.
|
|
@@ -73,7 +72,7 @@ export declare class QueryReference<T extends Data = Data> extends Query<T> impl
|
|
|
73
72
|
* @param next Observer with `next`, `error`, or `complete` methods or a `next()` dispatcher.
|
|
74
73
|
* @return Function that ends the subscription.
|
|
75
74
|
*/
|
|
76
|
-
subscribe(next: Observer<
|
|
75
|
+
subscribe(next: Observer<ImmutableArray<Entity<T>>> | Dispatcher<[ImmutableArray<Entity<T>>]>): Unsubscriber;
|
|
77
76
|
/**
|
|
78
77
|
* Set all matching documents to the same exact value.
|
|
79
78
|
*
|
|
@@ -93,21 +92,17 @@ export declare class QueryReference<T extends Data = Data> extends Query<T> impl
|
|
|
93
92
|
* @return Nothing (possibly promised).
|
|
94
93
|
*/
|
|
95
94
|
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
95
|
toString(): string;
|
|
101
96
|
}
|
|
102
97
|
/** A document reference within a specific database. */
|
|
103
|
-
export declare class DocumentReference<T extends Data = Data> implements Observable<Result<T>>,
|
|
98
|
+
export declare class DocumentReference<T extends Data = Data> implements Observable<Result<T>>, Reference {
|
|
104
99
|
readonly db: Database;
|
|
105
100
|
readonly validator: Validator<T>;
|
|
106
101
|
readonly collection: string;
|
|
107
102
|
readonly id: string;
|
|
108
103
|
constructor(db: Database, validator: Validator<T>, collection: string, id: string);
|
|
109
104
|
/** Create a query on this document's collection. */
|
|
110
|
-
query(filters?: FilterProps<T
|
|
105
|
+
query(filters?: FilterProps<Entity<T>>, sorts?: SortKeys<Entity<T>>, limit?: number | null): QueryReference<T>;
|
|
111
106
|
/** Get an 'optional' reference to this document (uses a `ModelQuery` with an `id` filter). */
|
|
112
107
|
get optional(): QueryReference<T>;
|
|
113
108
|
/**
|
|
@@ -117,17 +112,17 @@ export declare class DocumentReference<T extends Data = Data> implements Observa
|
|
|
117
112
|
get exists(): boolean | PromiseLike<boolean>;
|
|
118
113
|
/**
|
|
119
114
|
* Get the result of this document.
|
|
120
|
-
* @return Document's data, or `
|
|
115
|
+
* @return Document's data, or `null` if the document doesn't exist (possibly promised).
|
|
121
116
|
*/
|
|
122
|
-
get result():
|
|
117
|
+
get result(): Result<Entity<T>> | PromiseLike<Result<Entity<T>>>;
|
|
123
118
|
/**
|
|
124
119
|
* Get the data of this document.
|
|
125
120
|
* - Useful for destructuring, e.g. `{ name, title } = await documentThatMustExist.asyncData`
|
|
126
121
|
*
|
|
127
122
|
* @return Document's data (possibly promised).
|
|
128
|
-
* @throws RequiredError if the document
|
|
123
|
+
* @throws RequiredError if the document does not exist.
|
|
129
124
|
*/
|
|
130
|
-
get data():
|
|
125
|
+
get data(): Entity<T> | PromiseLike<Entity<T>>;
|
|
131
126
|
/**
|
|
132
127
|
* Subscribe to the result of this document (indefinitely).
|
|
133
128
|
* - `next()` is called once with the initial result, and again any time the result changes.
|
|
@@ -135,14 +130,12 @@ export declare class DocumentReference<T extends Data = Data> implements Observa
|
|
|
135
130
|
* @param next Observer with `next`, `error`, or `complete` methods or a `next()` dispatcher.
|
|
136
131
|
* @return Function that ends the subscription.
|
|
137
132
|
*/
|
|
138
|
-
subscribe(next: Observer<
|
|
133
|
+
subscribe(next: Observer<Result<Entity<T>>> | Dispatcher<[Result<Entity<T>>]>): Unsubscriber;
|
|
139
134
|
/** Set the complete data of this document. */
|
|
140
135
|
set(data: T): void | PromiseLike<void>;
|
|
141
136
|
/** Update this document. */
|
|
142
137
|
update(updates: DataUpdate<T> | PropUpdates<T>): void | PromiseLike<void>;
|
|
143
138
|
/** Delete this document. */
|
|
144
139
|
delete(): void | PromiseLike<void>;
|
|
145
|
-
/** Validate data for this query reference. */
|
|
146
|
-
validate(unsafeData: Data): T;
|
|
147
140
|
toString(): string;
|
|
148
141
|
}
|
package/db/Reference.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getArray } from "../util/array.js";
|
|
2
|
+
import { ArrayObserver } from "../util/observe.js";
|
|
3
3
|
import { Query } from "../query/Query.js";
|
|
4
4
|
import { Filters } from "../query/Filters.js";
|
|
5
5
|
import { Sorts } from "../query/Sorts.js";
|
|
6
|
-
import { callAsync
|
|
7
|
-
import { getMap } from "../util/map.js";
|
|
6
|
+
import { callAsync } from "../util/async.js";
|
|
8
7
|
import { countItems, hasItems } from "../util/iterate.js";
|
|
9
8
|
import { DataUpdate } from "../update/DataUpdate.js";
|
|
10
|
-
import { Feedback } from "../feedback/Feedback.js";
|
|
11
|
-
import { InvalidFeedback } from "../feedback/InvalidFeedback.js";
|
|
12
9
|
import { Filter } from "../query/Filter.js";
|
|
13
|
-
import {
|
|
14
|
-
import { DocumentResultObserver, getDocumentData, getDocumentResult, getQueryData, getQueryResult } from "./util.js";
|
|
10
|
+
import { getDocumentData, getQueryData, getQueryResult } from "./util.js";
|
|
15
11
|
/** A query reference within a specific database. */
|
|
16
12
|
export class QueryReference extends Query {
|
|
17
13
|
constructor(db, validator, collection, filters, sorts, limit) {
|
|
@@ -35,25 +31,25 @@ export class QueryReference extends Query {
|
|
|
35
31
|
return this.db.provider.add(this, data);
|
|
36
32
|
}
|
|
37
33
|
/**
|
|
38
|
-
* Get an iterable that yields the
|
|
34
|
+
* Get an iterable that yields the entities of this query.
|
|
39
35
|
* @return Map containing the results.
|
|
40
36
|
*/
|
|
41
|
-
get
|
|
37
|
+
get items() {
|
|
42
38
|
return this.db.provider.getQuery(this);
|
|
43
39
|
}
|
|
44
40
|
/**
|
|
45
|
-
* Get an
|
|
46
|
-
* @return
|
|
41
|
+
* Get an array of the results of this .
|
|
42
|
+
* @return Array containing the entities.
|
|
47
43
|
*/
|
|
48
|
-
get
|
|
49
|
-
return callAsync(
|
|
44
|
+
get array() {
|
|
45
|
+
return callAsync(getArray, this.db.provider.getQuery(this));
|
|
50
46
|
}
|
|
51
47
|
/**
|
|
52
48
|
* Count the number of results of this set of documents.
|
|
53
49
|
* @return Number of documents matching the query (possibly promised).
|
|
54
50
|
*/
|
|
55
51
|
get count() {
|
|
56
|
-
return callAsync(countItems, this.
|
|
52
|
+
return callAsync(countItems, this.items);
|
|
57
53
|
}
|
|
58
54
|
/**
|
|
59
55
|
* Does at least one document exist for this query?
|
|
@@ -63,16 +59,16 @@ export class QueryReference extends Query {
|
|
|
63
59
|
return callAsync(hasItems, this.db.provider.getQuery(this.max(1)));
|
|
64
60
|
}
|
|
65
61
|
/**
|
|
66
|
-
* Get
|
|
62
|
+
* Get the first document matched by this query or `null` if this query has no results.
|
|
67
63
|
*
|
|
68
64
|
* @return Entry in `[id, data]` format for the first document.
|
|
69
65
|
* @throws RequiredError if there were no results for this query.
|
|
70
66
|
*/
|
|
71
67
|
get result() {
|
|
72
|
-
return callAsync(getQueryResult, this.db.provider.getQuery(this.max(1))
|
|
68
|
+
return callAsync(getQueryResult, this.db.provider.getQuery(this.max(1)));
|
|
73
69
|
}
|
|
74
70
|
/**
|
|
75
|
-
* Get
|
|
71
|
+
* Get the first document matched by this query.
|
|
76
72
|
*
|
|
77
73
|
* @return Entry in `[id, data]` format for the first document.
|
|
78
74
|
* @throws RequiredError if there were no results for this query.
|
|
@@ -88,7 +84,7 @@ export class QueryReference extends Query {
|
|
|
88
84
|
* @return Function that ends the subscription.
|
|
89
85
|
*/
|
|
90
86
|
subscribe(next) {
|
|
91
|
-
return this.db.provider.subscribeQuery(this, new
|
|
87
|
+
return this.db.provider.subscribeQuery(this, new ArrayObserver(typeof next === "function" ? { next } : next));
|
|
92
88
|
}
|
|
93
89
|
/**
|
|
94
90
|
* Set all matching documents to the same exact value.
|
|
@@ -115,28 +111,6 @@ export class QueryReference extends Query {
|
|
|
115
111
|
delete() {
|
|
116
112
|
return this.db.provider.deleteQuery(this);
|
|
117
113
|
}
|
|
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
114
|
// Override to include the collection name.
|
|
141
115
|
toString() {
|
|
142
116
|
return `${this.collection}?${super.toString()}`;
|
|
@@ -167,17 +141,17 @@ export class DocumentReference {
|
|
|
167
141
|
}
|
|
168
142
|
/**
|
|
169
143
|
* Get the result of this document.
|
|
170
|
-
* @return Document's data, or `
|
|
144
|
+
* @return Document's data, or `null` if the document doesn't exist (possibly promised).
|
|
171
145
|
*/
|
|
172
146
|
get result() {
|
|
173
|
-
return
|
|
147
|
+
return this.db.provider.get(this);
|
|
174
148
|
}
|
|
175
149
|
/**
|
|
176
150
|
* Get the data of this document.
|
|
177
151
|
* - Useful for destructuring, e.g. `{ name, title } = await documentThatMustExist.asyncData`
|
|
178
152
|
*
|
|
179
153
|
* @return Document's data (possibly promised).
|
|
180
|
-
* @throws RequiredError if the document
|
|
154
|
+
* @throws RequiredError if the document does not exist.
|
|
181
155
|
*/
|
|
182
156
|
get data() {
|
|
183
157
|
return callAsync(getDocumentData, this.db.provider.get(this), this);
|
|
@@ -190,7 +164,7 @@ export class DocumentReference {
|
|
|
190
164
|
* @return Function that ends the subscription.
|
|
191
165
|
*/
|
|
192
166
|
subscribe(next) {
|
|
193
|
-
return this.db.provider.subscribe(this,
|
|
167
|
+
return this.db.provider.subscribe(this, typeof next === "function" ? { next } : next);
|
|
194
168
|
}
|
|
195
169
|
/** Set the complete data of this document. */
|
|
196
170
|
set(data) {
|
|
@@ -204,15 +178,6 @@ export class DocumentReference {
|
|
|
204
178
|
delete() {
|
|
205
179
|
return this.db.provider.delete(this);
|
|
206
180
|
}
|
|
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
|
-
}
|
|
215
|
-
}
|
|
216
181
|
// Implement toString()
|
|
217
182
|
toString() {
|
|
218
183
|
return `${this.collection}/${this.id}`;
|
package/db/errors.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { Data } from "../util/data.js";
|
|
2
|
-
import type { Feedback } from "../feedback/Feedback.js";
|
|
3
|
-
import { ValidationError } from "../error/ValidationError.js";
|
|
4
2
|
import { RequiredError } from "../error/RequiredError.js";
|
|
5
3
|
import type { DocumentReference, QueryReference } from "./Reference.js";
|
|
6
4
|
/** Thrown if a document doesn't exist. */
|
|
@@ -8,18 +6,8 @@ export declare class DocumentRequiredError<T extends Data> extends RequiredError
|
|
|
8
6
|
ref: DocumentReference<T>;
|
|
9
7
|
constructor(ref: DocumentReference<T>);
|
|
10
8
|
}
|
|
11
|
-
/** Thrown if a document can't validate. */
|
|
12
|
-
export declare class DocumentValidationError<T extends Data> extends ValidationError {
|
|
13
|
-
ref: DocumentReference<T>;
|
|
14
|
-
constructor(ref: DocumentReference<T>, feedback: Feedback);
|
|
15
|
-
}
|
|
16
9
|
/** Thrown if a query doesn't exist. */
|
|
17
10
|
export declare class QueryRequiredError<T extends Data> extends RequiredError {
|
|
18
11
|
ref: QueryReference<T>;
|
|
19
12
|
constructor(ref: QueryReference<T>);
|
|
20
13
|
}
|
|
21
|
-
/** Thrown if a query can't validate a set of results. */
|
|
22
|
-
export declare class QueryValidationError<T extends Data> extends ValidationError {
|
|
23
|
-
ref: QueryReference<T>;
|
|
24
|
-
constructor(ref: QueryReference<T>, feedback: Feedback);
|
|
25
|
-
}
|
package/db/errors.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ValidationError } from "../error/ValidationError.js";
|
|
2
1
|
import { RequiredError } from "../error/RequiredError.js";
|
|
3
2
|
/** Thrown if a document doesn't exist. */
|
|
4
3
|
export class DocumentRequiredError extends RequiredError {
|
|
@@ -8,14 +7,6 @@ export class DocumentRequiredError extends RequiredError {
|
|
|
8
7
|
}
|
|
9
8
|
}
|
|
10
9
|
DocumentRequiredError.prototype.name = "DocumentRequiredError";
|
|
11
|
-
/** Thrown if a document can't validate. */
|
|
12
|
-
export class DocumentValidationError extends ValidationError {
|
|
13
|
-
constructor(ref, feedback) {
|
|
14
|
-
super(`Invalid data for ${ref.toString()}`, feedback);
|
|
15
|
-
this.ref = ref;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
DocumentValidationError.prototype.name = "DocumentValidationError";
|
|
19
10
|
/** Thrown if a query doesn't exist. */
|
|
20
11
|
export class QueryRequiredError extends RequiredError {
|
|
21
12
|
constructor(ref) {
|
|
@@ -24,11 +15,3 @@ export class QueryRequiredError extends RequiredError {
|
|
|
24
15
|
}
|
|
25
16
|
}
|
|
26
17
|
QueryRequiredError.prototype.name = "QueryRequiredError";
|
|
27
|
-
/** Thrown if a query can't validate a set of results. */
|
|
28
|
-
export class QueryValidationError extends ValidationError {
|
|
29
|
-
constructor(ref, feedback) {
|
|
30
|
-
super(`Invalid documents for "${ref.collection}"`, feedback);
|
|
31
|
-
this.ref = ref;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
QueryValidationError.prototype.name = "QueryValidationError";
|
package/db/util.d.ts
CHANGED
|
@@ -1,37 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Entity } from "../util/data.js";
|
|
2
2
|
import { Data, Result } from "../util/data.js";
|
|
3
|
-
import type { Entries } from "../util/entry.js";
|
|
4
3
|
import type { DocumentReference, QueryReference, Reference } from "./Reference.js";
|
|
5
|
-
/** Database data embeds the corresponding `Document` instance and string ID into the data. */
|
|
6
|
-
export declare type DocumentData<T extends Data> = T & {
|
|
7
|
-
id: string;
|
|
8
|
-
doc: DocumentReference<T>;
|
|
9
|
-
};
|
|
10
4
|
/** Get the data for a document from a result for that document. */
|
|
11
|
-
export declare function getDocumentData<T extends Data>(result:
|
|
12
|
-
/** Is an unknown value a DocumentResult. */
|
|
13
|
-
export declare const isDocumentData: <T extends Data>(v: unknown) => v is DocumentData<T>;
|
|
14
|
-
/** Oserver that transforms a result into a document result. */
|
|
15
|
-
export declare class DocumentDataObserver<T extends Data> extends TransformableObserver<Result<T>, DocumentData<T>> {
|
|
16
|
-
protected _ref: DocumentReference<T>;
|
|
17
|
-
constructor(target: Observer<DocumentData<T>>, ref: DocumentReference<T>);
|
|
18
|
-
transform(result: Result<T>): DocumentData<T>;
|
|
19
|
-
}
|
|
20
|
-
/** Database result embeds the corresponding `Document` instance and string ID into the result. */
|
|
21
|
-
export declare type DocumentResult<T extends Data> = DocumentData<T> | null;
|
|
5
|
+
export declare function getDocumentData<T extends Data>(result: Result<Entity<T>>, ref: DocumentReference<T>): Entity<T>;
|
|
22
6
|
/** Get the data for a document from a result for that document. */
|
|
23
|
-
export declare function
|
|
24
|
-
/** Is an unknown value a DocumentResult. */
|
|
25
|
-
export declare const isDocumentResult: <T extends Data>(v: unknown) => v is DocumentResult<T>;
|
|
26
|
-
/** Oserver that transforms a set of entries into a results map. */
|
|
27
|
-
export declare class DocumentResultObserver<T extends Data> extends TransformableObserver<Result<T>, DocumentResult<T>> {
|
|
28
|
-
protected _ref: DocumentReference<T>;
|
|
29
|
-
constructor(target: Observer<DocumentResult<T>>, ref: DocumentReference<T>);
|
|
30
|
-
transform(result: Result<T>): DocumentResult<T>;
|
|
31
|
-
}
|
|
7
|
+
export declare function getQueryData<T extends Data>(entities: Iterable<Entity<T>>, ref: QueryReference<T>): Entity<T>;
|
|
32
8
|
/** Get the data for a document from a result for that document. */
|
|
33
|
-
export declare function
|
|
34
|
-
/** Get the data for a document from a result for that document. */
|
|
35
|
-
export declare function getQueryResult<T extends Data>(entries: Entries<T>, ref: QueryReference<T>): DocumentResult<T>;
|
|
9
|
+
export declare function getQueryResult<T extends Data>(entities: Iterable<Entity<T>>): Entity<T> | null;
|
|
36
10
|
/** Are two database references equal? */
|
|
37
11
|
export declare const isSameReference: (left: Reference, right: Reference) => boolean;
|
package/db/util.js
CHANGED
|
@@ -1,54 +1,21 @@
|
|
|
1
|
-
import { TransformableObserver } from "../util/observe.js";
|
|
2
|
-
import { isData } from "../util/data.js";
|
|
3
1
|
import { getFirstItem } from "../util/array.js";
|
|
4
2
|
import { DocumentRequiredError, QueryRequiredError } from "./errors.js";
|
|
5
3
|
/** Get the data for a document from a result for that document. */
|
|
6
4
|
export function getDocumentData(result, ref) {
|
|
7
5
|
if (result)
|
|
8
|
-
return
|
|
6
|
+
return result;
|
|
9
7
|
throw new DocumentRequiredError(ref);
|
|
10
8
|
}
|
|
11
|
-
/** Is an unknown value a DocumentResult. */
|
|
12
|
-
export const isDocumentData = (v) => isData(v) && "id" in v && "doc" in v;
|
|
13
|
-
/** Oserver that transforms a result into a document result. */
|
|
14
|
-
export class DocumentDataObserver extends TransformableObserver {
|
|
15
|
-
constructor(target, ref) {
|
|
16
|
-
super(target);
|
|
17
|
-
this._ref = ref;
|
|
18
|
-
}
|
|
19
|
-
transform(result) {
|
|
20
|
-
return getDocumentData(result, this._ref);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
/** Get the data for a document from a result for that document. */
|
|
24
|
-
export function getDocumentResult(result, ref) {
|
|
25
|
-
return result ? getDocumentData(result, ref) : null;
|
|
26
|
-
}
|
|
27
|
-
/** Is an unknown value a DocumentResult. */
|
|
28
|
-
export const isDocumentResult = (v) => isData(v) && "id" in v && "doc" in v;
|
|
29
|
-
/** Oserver that transforms a set of entries into a results map. */
|
|
30
|
-
export class DocumentResultObserver extends TransformableObserver {
|
|
31
|
-
constructor(target, ref) {
|
|
32
|
-
super(target);
|
|
33
|
-
this._ref = ref;
|
|
34
|
-
}
|
|
35
|
-
transform(result) {
|
|
36
|
-
return getDocumentResult(result, this._ref);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
9
|
/** Get the data for a document from a result for that document. */
|
|
40
|
-
export function getQueryData(
|
|
41
|
-
const
|
|
42
|
-
if (
|
|
43
|
-
return
|
|
10
|
+
export function getQueryData(entities, ref) {
|
|
11
|
+
const entity = getQueryResult(entities);
|
|
12
|
+
if (entity)
|
|
13
|
+
return entity;
|
|
44
14
|
throw new QueryRequiredError(ref);
|
|
45
15
|
}
|
|
46
16
|
/** Get the data for a document from a result for that document. */
|
|
47
|
-
export function getQueryResult(
|
|
48
|
-
|
|
49
|
-
if (first)
|
|
50
|
-
return getDocumentData(first[1], ref.doc(first[0]));
|
|
51
|
-
return null;
|
|
17
|
+
export function getQueryResult(entities) {
|
|
18
|
+
return getFirstItem(entities) || null;
|
|
52
19
|
}
|
|
53
20
|
/** Are two database references equal? */
|
|
54
21
|
export const isSameReference = (left, right) => left === right || left.toString() === right.toString();
|
|
@@ -1,7 +1,6 @@
|
|
|
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, Result, Entity } from "../../util/data.js";
|
|
5
4
|
import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
|
|
6
5
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
7
6
|
import { Observer, Unsubscriber } from "../../util/observe.js";
|
|
@@ -14,14 +13,14 @@ import { Observer, Unsubscriber } from "../../util/observe.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<T extends Data>(ref: DocumentReference<T>, observer: Observer<Result<T
|
|
16
|
+
get<T extends Data>(ref: DocumentReference<T>): Promise<Result<Entity<T>>>;
|
|
17
|
+
subscribe<T extends Data>(ref: DocumentReference<T>, observer: Observer<Result<Entity<T>>>): Unsubscriber;
|
|
19
18
|
add<T extends Data>(ref: QueryReference<T>, data: T): Promise<string>;
|
|
20
19
|
set<T extends Data>(ref: DocumentReference<T>, data: T): Promise<void>;
|
|
21
20
|
update<T extends Data>(ref: DocumentReference<T>, update: DataUpdate<T>): Promise<void>;
|
|
22
21
|
delete<T extends Data>(ref: DocumentReference<T>): Promise<void>;
|
|
23
|
-
getQuery<T extends Data>(ref: QueryReference<T>): Promise<
|
|
24
|
-
subscribeQuery<T extends Data>(ref: QueryReference<T>, observer: Observer<
|
|
22
|
+
getQuery<T extends Data>(ref: QueryReference<T>): Promise<Iterable<Entity<T>>>;
|
|
23
|
+
subscribeQuery<T extends Data>(ref: QueryReference<T>, observer: Observer<Iterable<Entity<T>>>): Unsubscriber;
|
|
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>;
|
|
@@ -49,7 +49,12 @@ function getQuery(firestore, ref) {
|
|
|
49
49
|
/** Create a set of results from a collection snapshot. */
|
|
50
50
|
function* getResults(snapshot) {
|
|
51
51
|
for (const s of snapshot.docs)
|
|
52
|
-
yield
|
|
52
|
+
yield { ...s.data(), id: s.id };
|
|
53
|
+
}
|
|
54
|
+
/** Get a result from a document snapshot. */
|
|
55
|
+
function getResult(snapshot) {
|
|
56
|
+
const data = snapshot.data();
|
|
57
|
+
return data ? { ...data, id: snapshot.id } : null;
|
|
53
58
|
}
|
|
54
59
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
55
60
|
function* yieldFieldValues(updates, prefix = "") {
|
|
@@ -84,10 +89,10 @@ export class FirestoreClientProvider extends Provider {
|
|
|
84
89
|
this.firestore = firestore;
|
|
85
90
|
}
|
|
86
91
|
async get(ref) {
|
|
87
|
-
return (await getDoc(getDocument(this.firestore, ref)))
|
|
92
|
+
return getResult(await getDoc(getDocument(this.firestore, ref)));
|
|
88
93
|
}
|
|
89
94
|
subscribe(ref, observer) {
|
|
90
|
-
return onSnapshot(getDocument(this.firestore, ref), snapshot => dispatchNext(observer, snapshot
|
|
95
|
+
return onSnapshot(getDocument(this.firestore, ref), snapshot => dispatchNext(observer, getResult(snapshot)), thrown => dispatchError(observer, thrown));
|
|
91
96
|
}
|
|
92
97
|
async add(ref, data) {
|
|
93
98
|
const reference = await addDoc(getCollection(this.firestore, ref), data);
|