shelving 1.71.1 → 1.72.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/Changes.d.ts +21 -0
- package/db/Changes.js +36 -0
- package/db/Database.d.ts +30 -19
- package/db/Database.js +27 -27
- package/db/DatabaseDocument.d.ts +87 -0
- package/db/DatabaseDocument.js +91 -0
- package/db/DatabaseQuery.d.ts +120 -0
- package/db/DatabaseQuery.js +120 -0
- package/db/index.d.ts +3 -2
- package/db/index.js +3 -2
- package/error/ValidationError.js +1 -1
- package/feedback/ErrorFeedback.d.ts +1 -1
- package/feedback/ErrorFeedback.js +1 -0
- package/feedback/Feedback.d.ts +15 -12
- package/feedback/Feedback.js +18 -26
- package/feedback/InvalidFeedback.d.ts +1 -1
- package/feedback/InvalidFeedback.js +1 -0
- package/feedback/SuccessFeedback.d.ts +1 -1
- package/feedback/SuccessFeedback.js +1 -0
- package/feedback/WarningFeedback.d.ts +1 -1
- package/feedback/WarningFeedback.js +1 -0
- package/firestore/client/FirestoreClientProvider.d.ts +14 -15
- package/firestore/client/FirestoreClientProvider.js +48 -46
- package/firestore/lite/FirestoreLiteProvider.d.ts +12 -13
- package/firestore/lite/FirestoreLiteProvider.js +44 -41
- package/firestore/server/FirestoreServerProvider.d.ts +14 -15
- package/firestore/server/FirestoreServerProvider.js +44 -42
- package/markup/regexp.d.ts +9 -1
- package/markup/regexp.js +0 -2
- package/markup/rules.d.ts +14 -1
- package/markup/rules.js +28 -19
- package/package.json +5 -5
- package/provider/BatchProvider.d.ts +11 -14
- package/provider/BatchProvider.js +29 -41
- package/provider/CacheProvider.d.ts +20 -21
- package/provider/CacheProvider.js +40 -29
- package/provider/DebugProvider.d.ts +36 -16
- package/provider/DebugProvider.js +150 -101
- package/provider/MemoryProvider.d.ts +19 -19
- package/provider/MemoryProvider.js +6 -9
- package/provider/Provider.d.ts +47 -50
- package/provider/Provider.js +7 -1
- package/provider/ThroughProvider.d.ts +38 -28
- package/provider/ThroughProvider.js +49 -6
- package/provider/ValidationProvider.d.ts +40 -14
- package/provider/ValidationProvider.js +84 -29
- package/query/Filter.d.ts +7 -3
- package/query/Filter.js +59 -37
- package/query/Filters.d.ts +5 -12
- package/query/Filters.js +10 -10
- package/query/Query.d.ts +11 -16
- package/query/Query.js +30 -30
- package/query/Rules.d.ts +0 -1
- package/query/Rules.js +0 -4
- package/query/Sort.d.ts +6 -3
- package/query/Sort.js +25 -7
- package/query/Sorts.d.ts +5 -5
- package/query/Sorts.js +9 -6
- package/react/useDocument.d.ts +8 -8
- package/react/useDocument.js +2 -3
- package/react/useQuery.d.ts +9 -13
- package/react/useQuery.js +6 -15
- package/react/useSubscribe.js +1 -2
- package/state/ObjectState.d.ts +2 -2
- package/state/State.d.ts +7 -4
- package/state/State.js +12 -9
- package/test/index.d.ts +2 -0
- package/test/util.d.ts +3 -3
- package/update/DataUpdate.d.ts +1 -1
- package/update/DataUpdate.js +7 -9
- package/update/ObjectUpdate.d.ts +2 -2
- package/update/ObjectUpdate.js +14 -4
- package/util/async.d.ts +14 -35
- package/util/async.js +48 -63
- package/util/data.d.ts +3 -16
- package/util/data.js +0 -4
- package/util/diff.d.ts +2 -1
- package/util/diff.js +2 -1
- package/util/entry.d.ts +14 -26
- package/util/entry.js +7 -6
- package/util/filter.d.ts +2 -2
- package/util/hydrate.d.ts +4 -4
- package/util/hydrate.js +29 -12
- package/util/index.d.ts +0 -1
- package/util/index.js +0 -1
- package/util/iterate.d.ts +11 -33
- package/util/iterate.js +26 -61
- package/util/jsx.d.ts +1 -1
- package/util/object.d.ts +1 -8
- package/util/object.js +8 -8
- package/util/sort.d.ts +2 -4
- package/util/sort.js +7 -8
- package/util/string.d.ts +15 -7
- package/util/string.js +13 -11
- package/util/transform.d.ts +5 -5
- package/util/transform.js +1 -1
- package/util/validate.d.ts +2 -2
- package/util/validate.js +16 -22
- package/db/Operation.d.ts +0 -79
- package/db/Operation.js +0 -129
- package/db/Reference.d.ts +0 -151
- package/db/Reference.js +0 -216
- package/util/constants.d.ts +0 -12
- package/util/constants.js +0 -12
package/feedback/Feedback.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ImmutableObject } from "../util/object.js";
|
|
2
2
|
/**
|
|
3
3
|
* The `Feedback` class represents a feedback message that should be shown to the user.
|
|
4
4
|
* - Basic `Feedback` is neither good nor bad, `SuccessFeedback` indicates good news, and `ErrorFeedback` indicates bad news.
|
|
@@ -10,18 +10,21 @@ import type { ImmutableObject } from "../util/object.js";
|
|
|
10
10
|
* @param feedback String feedback message that is safe to show to users.
|
|
11
11
|
* @param details Set of other `Feedback` instances describing the issue in further detail.
|
|
12
12
|
*/
|
|
13
|
-
export
|
|
13
|
+
export interface Feedback {
|
|
14
|
+
/** Name of the class (same as `Error`). */
|
|
15
|
+
name: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class Feedback<T = unknown> {
|
|
14
18
|
/** String feedback message that is safe to show to a user. */
|
|
15
19
|
readonly message: string;
|
|
16
20
|
/** Nested details providing deeper feedback. */
|
|
17
|
-
readonly
|
|
18
|
-
constructor(feedback: string,
|
|
19
|
-
/**
|
|
20
|
-
* Map details to a set of string messages.
|
|
21
|
-
* - If a detail is another `Feedback` instance, return its `.message` string.
|
|
22
|
-
* - If a detail is anything else, convert it to string using `toString()`
|
|
23
|
-
*/
|
|
24
|
-
get messages(): ImmutableObject<string>;
|
|
21
|
+
readonly value: T;
|
|
22
|
+
constructor(feedback: string, value?: T);
|
|
25
23
|
}
|
|
26
|
-
/** Is an unknown value a `Feedback`
|
|
27
|
-
export declare const isFeedback: <T extends Feedback
|
|
24
|
+
/** Is an unknown value a `Feedback` object. */
|
|
25
|
+
export declare const isFeedback: <T extends Feedback<unknown>>(v: unknown) => v is Feedback<unknown>;
|
|
26
|
+
/**
|
|
27
|
+
* Get an object of sub-messages in `{ key: message }` format from a feedback's value.
|
|
28
|
+
* - Takes the `.value` property from a `Feedback` instance and looks for keyed `Feedback` instances in either `{ key: Feedback }`. `Feedback[]`, or `Map<key, Feedback>` formats.
|
|
29
|
+
*/
|
|
30
|
+
export declare const getFeedbackMessages: ({ value }: Feedback) => ImmutableObject<string>;
|
package/feedback/Feedback.js
CHANGED
|
@@ -1,30 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
/**
|
|
4
|
-
* The `Feedback` class represents a feedback message that should be shown to the user.
|
|
5
|
-
* - Basic `Feedback` is neither good nor bad, `SuccessFeedback` indicates good news, and `ErrorFeedback` indicates bad news.
|
|
6
|
-
*
|
|
7
|
-
* Conceptually different to a Javascript `Error`...
|
|
8
|
-
* - `Error`: a program error designed to help developers fix an issue in their code.
|
|
9
|
-
* - `Feedback`: generated in reaction to something a user did, and helps them understand what to do next.
|
|
10
|
-
*
|
|
11
|
-
* @param feedback String feedback message that is safe to show to users.
|
|
12
|
-
* @param details Set of other `Feedback` instances describing the issue in further detail.
|
|
13
|
-
*/
|
|
1
|
+
import { getEntries } from "../util/entry.js";
|
|
2
|
+
import { isObject } from "../util/object.js";
|
|
14
3
|
export class Feedback {
|
|
15
|
-
constructor(feedback,
|
|
4
|
+
constructor(feedback, value) {
|
|
16
5
|
this.message = feedback;
|
|
17
|
-
this.
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Map details to a set of string messages.
|
|
21
|
-
* - If a detail is another `Feedback` instance, return its `.message` string.
|
|
22
|
-
* - If a detail is anything else, convert it to string using `toString()`
|
|
23
|
-
*/
|
|
24
|
-
get messages() {
|
|
25
|
-
return mapObject(this.details, _getMessage);
|
|
6
|
+
this.value = value;
|
|
26
7
|
}
|
|
27
8
|
}
|
|
28
|
-
|
|
29
|
-
/** Is an unknown value a `Feedback`
|
|
30
|
-
export const isFeedback = (v) => v
|
|
9
|
+
Feedback.prototype.name = "Feedback";
|
|
10
|
+
/** Is an unknown value a `Feedback` object. */
|
|
11
|
+
export const isFeedback = (v) => isObject(v) && typeof v.name === "string" && v.name.endsWith("Feedback") && typeof v.message === "string";
|
|
12
|
+
/**
|
|
13
|
+
* Get an object of sub-messages in `{ key: message }` format from a feedback's value.
|
|
14
|
+
* - Takes the `.value` property from a `Feedback` instance and looks for keyed `Feedback` instances in either `{ key: Feedback }`. `Feedback[]`, or `Map<key, Feedback>` formats.
|
|
15
|
+
*/
|
|
16
|
+
export const getFeedbackMessages = ({ value }) => Object.fromEntries(_yieldFeedbackMessages(value));
|
|
17
|
+
function* _yieldFeedbackMessages(value) {
|
|
18
|
+
if (isObject(value))
|
|
19
|
+
for (const [k, v] of getEntries(value))
|
|
20
|
+
if (isFeedback(v))
|
|
21
|
+
yield [k, v.message];
|
|
22
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ErrorFeedback } from "./ErrorFeedback.js";
|
|
2
2
|
/** Specific type of `ErrorFeedback` returned from `validate()` when a value is invalid. */
|
|
3
|
-
export declare class InvalidFeedback extends ErrorFeedback {
|
|
3
|
+
export declare class InvalidFeedback<T = unknown> extends ErrorFeedback<T> {
|
|
4
4
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { Firestore } from "firebase/firestore";
|
|
2
|
-
import type {
|
|
3
|
-
import type { Data, Entities, OptionalEntity } from "../../util/data.js";
|
|
2
|
+
import type { Entities, OptionalEntity, Datas, Key } from "../../util/data.js";
|
|
4
3
|
import type { Unsubscribe } from "../../observe/Observable.js";
|
|
4
|
+
import type { AsyncProvider, ProviderCollection, ProviderDocument, ProviderQuery } from "../../provider/Provider.js";
|
|
5
5
|
import { Observer } from "../../observe/Observer.js";
|
|
6
|
-
import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
|
|
7
6
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
8
7
|
/**
|
|
9
8
|
* Firestore client database provider.
|
|
@@ -11,18 +10,18 @@ import { DataUpdate } from "../../update/DataUpdate.js";
|
|
|
11
10
|
* - Supports offline mode.
|
|
12
11
|
* - Supports realtime subscriptions.
|
|
13
12
|
*/
|
|
14
|
-
export declare class FirestoreClientProvider extends
|
|
13
|
+
export declare class FirestoreClientProvider<T extends Datas> implements AsyncProvider<T> {
|
|
15
14
|
readonly firestore: Firestore;
|
|
16
15
|
constructor(firestore: Firestore);
|
|
17
|
-
getDocument<
|
|
18
|
-
subscribeDocument<
|
|
19
|
-
addDocument<
|
|
20
|
-
setDocument<
|
|
21
|
-
updateDocument<
|
|
22
|
-
deleteDocument<
|
|
23
|
-
getQuery<
|
|
24
|
-
subscribeQuery<
|
|
25
|
-
setQuery<
|
|
26
|
-
updateQuery<
|
|
27
|
-
deleteQuery<
|
|
16
|
+
getDocument<K extends Key<T>>(ref: ProviderDocument<T, K>): Promise<OptionalEntity<T[K]>>;
|
|
17
|
+
subscribeDocument<K extends Key<T>>(ref: ProviderDocument<T, K>, observer: Observer<OptionalEntity<T[K]>>): Unsubscribe;
|
|
18
|
+
addDocument<K extends Key<T>>(ref: ProviderCollection<T, K>, data: T[K]): Promise<string>;
|
|
19
|
+
setDocument<K extends Key<T>>(ref: ProviderDocument<T, K>, data: T[K]): Promise<void>;
|
|
20
|
+
updateDocument<K extends Key<T>>(ref: ProviderDocument<T, K>, update: DataUpdate<T[K]>): Promise<void>;
|
|
21
|
+
deleteDocument<K extends Key<T>>(ref: ProviderDocument<T, K>): Promise<void>;
|
|
22
|
+
getQuery<K extends Key<T>>(ref: ProviderQuery<T, K>): Promise<Entities<T[K]>>;
|
|
23
|
+
subscribeQuery<K extends Key<T>>(ref: ProviderQuery<T, K>, observer: Observer<Entities<T[K]>>): Unsubscribe;
|
|
24
|
+
setQuery<K extends Key<T>>(ref: ProviderQuery<T, K>, data: T[K]): Promise<number>;
|
|
25
|
+
updateQuery<K extends Key<T>>(ref: ProviderQuery<T, K>, update: DataUpdate<T[K]>): Promise<number>;
|
|
26
|
+
deleteQuery<K extends Key<T>>(ref: ProviderQuery<T, K>): Promise<number>;
|
|
28
27
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { orderBy as firestoreOrderBy, where as firestoreWhere, limit as firestoreLimit, increment as firestoreIncrement, arrayUnion as firestoreArrayUnion, arrayRemove as firestoreArrayRemove, deleteField as firestoreDeleteField, collection as firestoreCollection, doc as firestoreDocument, query as firestoreQuery, onSnapshot, addDoc, setDoc, updateDoc, deleteDoc, getDoc, getDocs, } from "firebase/firestore";
|
|
2
2
|
import { dispatchError, dispatchNext } from "../../observe/Observer.js";
|
|
3
|
-
import { UnsupportedError } from "../../error/UnsupportedError.js";
|
|
4
|
-
import { Provider } from "../../provider/Provider.js";
|
|
5
3
|
import { ArrayUpdate } from "../../update/ArrayUpdate.js";
|
|
6
4
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
7
5
|
import { Increment } from "../../update/Increment.js";
|
|
@@ -28,19 +26,19 @@ const DIRECTIONS = {
|
|
|
28
26
|
ASC: "asc",
|
|
29
27
|
DESC: "desc",
|
|
30
28
|
};
|
|
31
|
-
/** Get a Firestore
|
|
32
|
-
function
|
|
29
|
+
/** Get a Firestore DatabaseDocument for a given document. */
|
|
30
|
+
function _getDocument(firestore, { collection, id }) {
|
|
33
31
|
return firestoreDocument(firestore, collection, id);
|
|
34
32
|
}
|
|
35
33
|
/** Get a Firestore CollectionReference for a given query. */
|
|
36
|
-
function
|
|
34
|
+
function _getCollection(firestore, { collection }) {
|
|
37
35
|
return firestoreCollection(firestore, collection);
|
|
38
36
|
}
|
|
39
|
-
/**
|
|
40
|
-
function
|
|
41
|
-
return firestoreQuery(
|
|
37
|
+
/** Get a Firestore QueryReference for a given query. */
|
|
38
|
+
function _getQuery(firestore, ref) {
|
|
39
|
+
return firestoreQuery(_getCollection(firestore, ref), ..._yieldQueryConstraints(ref));
|
|
42
40
|
}
|
|
43
|
-
function*
|
|
41
|
+
function* _yieldQueryConstraints({ sorts, filters, limit }) {
|
|
44
42
|
for (const { key, direction } of sorts)
|
|
45
43
|
yield firestoreOrderBy(key === "id" ? ID : key, DIRECTIONS[direction]);
|
|
46
44
|
for (const { operator, key, value } of filters)
|
|
@@ -48,38 +46,44 @@ function* yieldQueryConstraints({ sorts, filters, limit }) {
|
|
|
48
46
|
if (typeof limit === "number")
|
|
49
47
|
yield firestoreLimit(limit);
|
|
50
48
|
}
|
|
51
|
-
function
|
|
52
|
-
return snapshot.docs.map(
|
|
49
|
+
function _getEntities(snapshot) {
|
|
50
|
+
return snapshot.docs.map(_getEntity);
|
|
53
51
|
}
|
|
54
|
-
function
|
|
52
|
+
function _getEntity(snapshot) {
|
|
55
53
|
const data = snapshot.data();
|
|
56
54
|
return { ...data, id: snapshot.id };
|
|
57
55
|
}
|
|
58
|
-
function
|
|
56
|
+
function _getOptionalEntity(snapshot) {
|
|
59
57
|
const data = snapshot.data();
|
|
60
58
|
return data ? { ...data, id: snapshot.id } : null;
|
|
61
59
|
}
|
|
62
60
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
63
|
-
function*
|
|
61
|
+
function* _getFieldValues(updates, prefix = "") {
|
|
64
62
|
for (const [key, update] of updates) {
|
|
65
|
-
if (
|
|
66
|
-
yield
|
|
67
|
-
|
|
68
|
-
yield [`${prefix}${key}`, firestoreDeleteField()];
|
|
69
|
-
else if (update instanceof Increment)
|
|
70
|
-
yield [`${prefix}${key}`, firestoreIncrement(update.amount)];
|
|
71
|
-
else if (update instanceof DataUpdate || update instanceof ObjectUpdate)
|
|
72
|
-
yield* yieldFieldValues(update, `${prefix}${key}.`);
|
|
63
|
+
if (update instanceof DataUpdate || update instanceof ObjectUpdate) {
|
|
64
|
+
yield* _getFieldValues(update, `${prefix}${key}.`);
|
|
65
|
+
}
|
|
73
66
|
else if (update instanceof ArrayUpdate) {
|
|
74
|
-
if (update.adds.length
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
yield
|
|
67
|
+
if (update.adds.length) {
|
|
68
|
+
yield `${prefix}${key}`;
|
|
69
|
+
yield firestoreArrayUnion(...update.adds);
|
|
70
|
+
}
|
|
71
|
+
if (update.deletes.length) {
|
|
72
|
+
yield `${prefix}${key}`;
|
|
73
|
+
yield firestoreArrayRemove(...update.deletes);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
yield `${prefix}${key}`;
|
|
78
|
+
if (!(update instanceof Update))
|
|
79
|
+
yield update;
|
|
80
|
+
else if (update instanceof Delete)
|
|
81
|
+
yield firestoreDeleteField();
|
|
82
|
+
else if (update instanceof Increment)
|
|
83
|
+
yield firestoreIncrement(update.amount);
|
|
84
|
+
else
|
|
85
|
+
yield update.transform();
|
|
80
86
|
}
|
|
81
|
-
else
|
|
82
|
-
yield [`${prefix}${key}`, update.transform()];
|
|
83
87
|
}
|
|
84
88
|
}
|
|
85
89
|
/**
|
|
@@ -88,50 +92,48 @@ function* yieldFieldValues(updates, prefix = "") {
|
|
|
88
92
|
* - Supports offline mode.
|
|
89
93
|
* - Supports realtime subscriptions.
|
|
90
94
|
*/
|
|
91
|
-
export class FirestoreClientProvider
|
|
95
|
+
export class FirestoreClientProvider {
|
|
92
96
|
constructor(firestore) {
|
|
93
|
-
super();
|
|
94
97
|
this.firestore = firestore;
|
|
95
98
|
}
|
|
96
99
|
async getDocument(ref) {
|
|
97
|
-
return
|
|
100
|
+
return _getOptionalEntity(await getDoc(_getDocument(this.firestore, ref)));
|
|
98
101
|
}
|
|
99
102
|
subscribeDocument(ref, observer) {
|
|
100
|
-
return onSnapshot(
|
|
103
|
+
return onSnapshot(_getDocument(this.firestore, ref), snapshot => dispatchNext(observer, _getOptionalEntity(snapshot)), thrown => dispatchError(observer, thrown));
|
|
101
104
|
}
|
|
102
105
|
async addDocument(ref, data) {
|
|
103
|
-
const reference = await addDoc(
|
|
106
|
+
const reference = await addDoc(_getCollection(this.firestore, ref), data);
|
|
104
107
|
return reference.id;
|
|
105
108
|
}
|
|
106
109
|
async setDocument(ref, data) {
|
|
107
|
-
await setDoc(
|
|
110
|
+
await setDoc(_getDocument(this.firestore, ref), data);
|
|
108
111
|
}
|
|
109
112
|
async updateDocument(ref, update) {
|
|
110
|
-
|
|
111
|
-
await updateDoc(getDocument(this.firestore, ref), fieldValues);
|
|
113
|
+
await updateDoc(_getDocument(this.firestore, ref), ..._getFieldValues(update));
|
|
112
114
|
}
|
|
113
115
|
async deleteDocument(ref) {
|
|
114
|
-
await deleteDoc(
|
|
116
|
+
await deleteDoc(_getDocument(this.firestore, ref));
|
|
115
117
|
}
|
|
116
118
|
async getQuery(ref) {
|
|
117
|
-
return
|
|
119
|
+
return _getEntities(await getDocs(_getQuery(this.firestore, ref)));
|
|
118
120
|
}
|
|
119
121
|
subscribeQuery(ref, observer) {
|
|
120
|
-
return onSnapshot(
|
|
122
|
+
return onSnapshot(_getQuery(this.firestore, ref), snapshot => dispatchNext(observer, _getEntities(snapshot)), thrown => dispatchError(observer, thrown));
|
|
121
123
|
}
|
|
122
124
|
async setQuery(ref, data) {
|
|
123
|
-
const snapshot = await getDocs(
|
|
125
|
+
const snapshot = await getDocs(_getQuery(this.firestore, ref));
|
|
124
126
|
await Promise.all(snapshot.docs.map(s => setDoc(s.ref, data)));
|
|
125
127
|
return snapshot.size;
|
|
126
128
|
}
|
|
127
129
|
async updateQuery(ref, update) {
|
|
128
|
-
const snapshot = await getDocs(
|
|
129
|
-
const fieldValues =
|
|
130
|
-
await Promise.all(snapshot.docs.map(s => updateDoc(s.ref, fieldValues)));
|
|
130
|
+
const snapshot = await getDocs(_getQuery(this.firestore, ref));
|
|
131
|
+
const fieldValues = Array.from(_getFieldValues(update));
|
|
132
|
+
await Promise.all(snapshot.docs.map(s => updateDoc(s.ref, ...fieldValues)));
|
|
131
133
|
return snapshot.size;
|
|
132
134
|
}
|
|
133
135
|
async deleteQuery(ref) {
|
|
134
|
-
const snapshot = await getDocs(
|
|
136
|
+
const snapshot = await getDocs(_getQuery(this.firestore, ref));
|
|
135
137
|
await Promise.all(snapshot.docs.map(s => deleteDoc(s.ref)));
|
|
136
138
|
return snapshot.size;
|
|
137
139
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { Firestore } from "firebase/firestore/lite";
|
|
2
|
-
import type {
|
|
3
|
-
import type { Data, Entities, OptionalEntity } from "../../util/data.js";
|
|
2
|
+
import type { Entities, OptionalEntity, Datas, Key } from "../../util/data.js";
|
|
4
3
|
import type { Unsubscribe } from "../../observe/Observable.js";
|
|
5
|
-
import {
|
|
4
|
+
import type { AsyncProvider, ProviderCollection, ProviderDocument, ProviderQuery } from "../../provider/Provider.js";
|
|
6
5
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
7
6
|
/**
|
|
8
7
|
* Firestore Lite client database provider.
|
|
@@ -10,18 +9,18 @@ import { DataUpdate } from "../../update/DataUpdate.js";
|
|
|
10
9
|
* - Does not support offline mode.
|
|
11
10
|
* - Does not support realtime subscriptions.
|
|
12
11
|
*/
|
|
13
|
-
export declare class
|
|
12
|
+
export declare class FirestoreLiteProvider<T extends Datas> implements AsyncProvider<T> {
|
|
14
13
|
readonly firestore: Firestore;
|
|
15
14
|
constructor(firestore: Firestore);
|
|
16
|
-
getDocument<
|
|
15
|
+
getDocument<K extends Key<T>>(ref: ProviderDocument<T, K>): Promise<OptionalEntity<T[K]>>;
|
|
17
16
|
subscribeDocument(): Unsubscribe;
|
|
18
|
-
addDocument<
|
|
19
|
-
setDocument<
|
|
20
|
-
updateDocument<
|
|
21
|
-
deleteDocument<
|
|
22
|
-
getQuery<
|
|
17
|
+
addDocument<K extends Key<T>>(ref: ProviderCollection<T, K>, data: T[K]): Promise<string>;
|
|
18
|
+
setDocument<K extends Key<T>>(ref: ProviderDocument<T, K>, data: T[K]): Promise<void>;
|
|
19
|
+
updateDocument<K extends Key<T>>(ref: ProviderDocument<T, K>, update: DataUpdate<T[K]>): Promise<void>;
|
|
20
|
+
deleteDocument<K extends Key<T>>(ref: ProviderDocument<T, K>): Promise<void>;
|
|
21
|
+
getQuery<K extends Key<T>>(ref: ProviderQuery<T, K>): Promise<Entities<T[K]>>;
|
|
23
22
|
subscribeQuery(): Unsubscribe;
|
|
24
|
-
setQuery<
|
|
25
|
-
updateQuery<
|
|
26
|
-
deleteQuery<
|
|
23
|
+
setQuery<K extends Key<T>>(ref: ProviderQuery<T, K>, data: T[K]): Promise<number>;
|
|
24
|
+
updateQuery<K extends Key<T>>(ref: ProviderQuery<T, K>, update: DataUpdate<T[K]>): Promise<number>;
|
|
25
|
+
deleteQuery<K extends Key<T>>(ref: ProviderQuery<T, K>): Promise<number>;
|
|
27
26
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { orderBy as firestoreOrderBy, where as firestoreWhere, limit as firestoreLimit, increment as firestoreIncrement, arrayUnion as firestoreArrayUnion, arrayRemove as firestoreArrayRemove, deleteField as firestoreDeleteField, collection as firestoreCollection, doc as firestoreDocument, query as firestoreQuery, setDoc, addDoc, updateDoc, deleteDoc, getDoc, getDocs, } from "firebase/firestore/lite";
|
|
2
2
|
import { UnsupportedError } from "../../error/UnsupportedError.js";
|
|
3
|
-
import { Provider } from "../../provider/Provider.js";
|
|
4
3
|
import { ArrayUpdate } from "../../update/ArrayUpdate.js";
|
|
5
4
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
6
5
|
import { Increment } from "../../update/Increment.js";
|
|
@@ -28,18 +27,18 @@ const DIRECTIONS = {
|
|
|
28
27
|
DESC: "desc",
|
|
29
28
|
};
|
|
30
29
|
/** Get a Firestore DocumentReference for a given document. */
|
|
31
|
-
function
|
|
30
|
+
function _getDocument(firestore, { collection, id }) {
|
|
32
31
|
return firestoreDocument(firestore, collection, id);
|
|
33
32
|
}
|
|
34
33
|
/** Get a Firestore CollectionReference for a given query. */
|
|
35
|
-
function
|
|
34
|
+
function _getCollection(firestore, { collection }) {
|
|
36
35
|
return firestoreCollection(firestore, collection);
|
|
37
36
|
}
|
|
38
37
|
/** Create a corresponding `QueryReference` from a Query. */
|
|
39
|
-
function
|
|
40
|
-
return firestoreQuery(
|
|
38
|
+
function _getQuery(firestore, ref) {
|
|
39
|
+
return firestoreQuery(_getCollection(firestore, ref), ..._yieldQueryConstraints(ref));
|
|
41
40
|
}
|
|
42
|
-
function*
|
|
41
|
+
function* _yieldQueryConstraints({ sorts, filters, limit }) {
|
|
43
42
|
for (const { key, direction } of sorts)
|
|
44
43
|
yield firestoreOrderBy(key === "id" ? ID : key, DIRECTIONS[direction]);
|
|
45
44
|
for (const { operator, key, value } of filters)
|
|
@@ -47,38 +46,44 @@ function* yieldQueryConstraints({ sorts, filters, limit }) {
|
|
|
47
46
|
if (typeof limit === "number")
|
|
48
47
|
yield firestoreLimit(limit);
|
|
49
48
|
}
|
|
50
|
-
function
|
|
51
|
-
return snapshot.docs.map(
|
|
49
|
+
function _getEntities(snapshot) {
|
|
50
|
+
return snapshot.docs.map(_getEntity);
|
|
52
51
|
}
|
|
53
|
-
function
|
|
52
|
+
function _getEntity(snapshot) {
|
|
54
53
|
const data = snapshot.data();
|
|
55
54
|
return { ...data, id: snapshot.id };
|
|
56
55
|
}
|
|
57
|
-
function
|
|
56
|
+
function _getOptionalData(snapshot) {
|
|
58
57
|
const data = snapshot.data();
|
|
59
58
|
return data ? { ...data, id: snapshot.id } : null;
|
|
60
59
|
}
|
|
61
60
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
62
|
-
function*
|
|
61
|
+
function* _getFieldValues(updates, prefix = "") {
|
|
63
62
|
for (const [key, update] of updates) {
|
|
64
|
-
if (
|
|
65
|
-
yield
|
|
66
|
-
|
|
67
|
-
yield [`${prefix}${key}`, firestoreDeleteField()];
|
|
68
|
-
else if (update instanceof Increment)
|
|
69
|
-
yield [`${prefix}${key}`, firestoreIncrement(update.amount)];
|
|
70
|
-
else if (update instanceof DataUpdate || update instanceof ObjectUpdate)
|
|
71
|
-
yield* yieldFieldValues(update, `${prefix}${key}.`);
|
|
63
|
+
if (update instanceof DataUpdate || update instanceof ObjectUpdate) {
|
|
64
|
+
yield* _getFieldValues(update, `${prefix}${key}.`);
|
|
65
|
+
}
|
|
72
66
|
else if (update instanceof ArrayUpdate) {
|
|
73
|
-
if (update.adds.length
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
yield
|
|
67
|
+
if (update.adds.length) {
|
|
68
|
+
yield `${prefix}${key}`;
|
|
69
|
+
yield firestoreArrayUnion(...update.adds);
|
|
70
|
+
}
|
|
71
|
+
if (update.deletes.length) {
|
|
72
|
+
yield `${prefix}${key}`;
|
|
73
|
+
yield firestoreArrayRemove(...update.deletes);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
yield `${prefix}${key}`;
|
|
78
|
+
if (!(update instanceof Update))
|
|
79
|
+
yield update;
|
|
80
|
+
else if (update instanceof Delete)
|
|
81
|
+
yield firestoreDeleteField();
|
|
82
|
+
else if (update instanceof Increment)
|
|
83
|
+
yield firestoreIncrement(update.amount);
|
|
84
|
+
else
|
|
85
|
+
yield update.transform();
|
|
79
86
|
}
|
|
80
|
-
else
|
|
81
|
-
yield [`${prefix}${key}`, update.transform()];
|
|
82
87
|
}
|
|
83
88
|
}
|
|
84
89
|
/**
|
|
@@ -87,50 +92,48 @@ function* yieldFieldValues(updates, prefix = "") {
|
|
|
87
92
|
* - Does not support offline mode.
|
|
88
93
|
* - Does not support realtime subscriptions.
|
|
89
94
|
*/
|
|
90
|
-
export class
|
|
95
|
+
export class FirestoreLiteProvider {
|
|
91
96
|
constructor(firestore) {
|
|
92
|
-
super();
|
|
93
97
|
this.firestore = firestore;
|
|
94
98
|
}
|
|
95
99
|
async getDocument(ref) {
|
|
96
|
-
return
|
|
100
|
+
return _getOptionalData(await getDoc(_getDocument(this.firestore, ref)));
|
|
97
101
|
}
|
|
98
102
|
subscribeDocument() {
|
|
99
103
|
throw new UnsupportedError("FirestoreLiteProvider does not support realtime subscriptions");
|
|
100
104
|
}
|
|
101
105
|
async addDocument(ref, data) {
|
|
102
|
-
const reference = await addDoc(
|
|
106
|
+
const reference = await addDoc(_getCollection(this.firestore, ref), data);
|
|
103
107
|
return reference.id;
|
|
104
108
|
}
|
|
105
109
|
async setDocument(ref, data) {
|
|
106
|
-
await setDoc(
|
|
110
|
+
await setDoc(_getDocument(this.firestore, ref), data);
|
|
107
111
|
}
|
|
108
112
|
async updateDocument(ref, update) {
|
|
109
|
-
|
|
110
|
-
await updateDoc(getDocument(this.firestore, ref), fieldValues);
|
|
113
|
+
await updateDoc(_getDocument(this.firestore, ref), ..._getFieldValues(update));
|
|
111
114
|
}
|
|
112
115
|
async deleteDocument(ref) {
|
|
113
|
-
await deleteDoc(
|
|
116
|
+
await deleteDoc(_getDocument(this.firestore, ref));
|
|
114
117
|
}
|
|
115
118
|
async getQuery(ref) {
|
|
116
|
-
return
|
|
119
|
+
return _getEntities(await getDocs(_getQuery(this.firestore, ref)));
|
|
117
120
|
}
|
|
118
121
|
subscribeQuery() {
|
|
119
122
|
throw new UnsupportedError("FirestoreLiteProvider does not support realtime subscriptions");
|
|
120
123
|
}
|
|
121
124
|
async setQuery(ref, data) {
|
|
122
|
-
const snapshot = await getDocs(
|
|
125
|
+
const snapshot = await getDocs(_getQuery(this.firestore, ref));
|
|
123
126
|
await Promise.all(snapshot.docs.map(s => setDoc(s.ref, data)));
|
|
124
127
|
return snapshot.size;
|
|
125
128
|
}
|
|
126
129
|
async updateQuery(ref, update) {
|
|
127
|
-
const snapshot = await getDocs(
|
|
128
|
-
const fieldValues =
|
|
129
|
-
await Promise.all(snapshot.docs.map(s => updateDoc(s.ref, fieldValues)));
|
|
130
|
+
const snapshot = await getDocs(_getQuery(this.firestore, ref));
|
|
131
|
+
const fieldValues = Array.from(_getFieldValues(update));
|
|
132
|
+
await Promise.all(snapshot.docs.map(s => updateDoc(s.ref, ...fieldValues)));
|
|
130
133
|
return snapshot.size;
|
|
131
134
|
}
|
|
132
135
|
async deleteQuery(ref) {
|
|
133
|
-
const snapshot = await getDocs(
|
|
136
|
+
const snapshot = await getDocs(_getQuery(this.firestore, ref));
|
|
134
137
|
await Promise.all(snapshot.docs.map(s => deleteDoc(s.ref)));
|
|
135
138
|
return snapshot.size;
|
|
136
139
|
}
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import { Firestore } from "@google-cloud/firestore";
|
|
2
|
-
import type {
|
|
3
|
-
import type { Data, Entities, OptionalEntity } from "../../util/data.js";
|
|
2
|
+
import type { Entities, OptionalEntity, Datas, Key } from "../../util/data.js";
|
|
4
3
|
import type { Unsubscribe } from "../../observe/Observable.js";
|
|
4
|
+
import type { AsyncProvider, ProviderCollection, ProviderDocument, ProviderQuery } from "../../provider/Provider.js";
|
|
5
5
|
import { Observer } from "../../observe/Observer.js";
|
|
6
|
-
import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
|
|
7
6
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
8
7
|
/**
|
|
9
8
|
* Firestore server database provider.
|
|
10
9
|
* - Works with the Firebase Admin SDK for Node.JS
|
|
11
10
|
*/
|
|
12
|
-
export declare class FirestoreServerProvider extends
|
|
11
|
+
export declare class FirestoreServerProvider<T extends Datas> implements AsyncProvider<T> {
|
|
13
12
|
readonly firestore: Firestore;
|
|
14
13
|
constructor(firestore?: Firestore);
|
|
15
|
-
getDocument<
|
|
16
|
-
subscribeDocument<
|
|
17
|
-
addDocument<
|
|
18
|
-
setDocument<
|
|
19
|
-
updateDocument<
|
|
20
|
-
deleteDocument<
|
|
21
|
-
getQuery<
|
|
22
|
-
subscribeQuery<
|
|
23
|
-
setQuery<
|
|
24
|
-
updateQuery<
|
|
25
|
-
deleteQuery<
|
|
14
|
+
getDocument<K extends Key<T>>(ref: ProviderDocument<T, K>): Promise<OptionalEntity<T[K]>>;
|
|
15
|
+
subscribeDocument<K extends Key<T>>(ref: ProviderDocument<T, K>, observer: Observer<OptionalEntity<T[K]>>): Unsubscribe;
|
|
16
|
+
addDocument<K extends Key<T>>(ref: ProviderCollection<T, K>, data: T[K]): Promise<string>;
|
|
17
|
+
setDocument<K extends Key<T>>(ref: ProviderDocument<T, K>, data: T[K]): Promise<void>;
|
|
18
|
+
updateDocument<K extends Key<T>>(ref: ProviderDocument<T, K>, update: DataUpdate<T[K]>): Promise<void>;
|
|
19
|
+
deleteDocument<K extends Key<T>>(ref: ProviderDocument<T, K>): Promise<void>;
|
|
20
|
+
getQuery<K extends Key<T>>(ref: ProviderQuery<T, K>): Promise<Entities<T[K]>>;
|
|
21
|
+
subscribeQuery<K extends Key<T>>(ref: ProviderQuery<T, K>, observer: Observer<Entities<T[K]>>): Unsubscribe;
|
|
22
|
+
setQuery<K extends Key<T>>(ref: ProviderQuery<T, K>, data: T[K]): Promise<number>;
|
|
23
|
+
updateQuery<K extends Key<T>>(ref: ProviderQuery<T, K>, update: DataUpdate<T[K]>): Promise<number>;
|
|
24
|
+
deleteQuery<K extends Key<T>>(ref: ProviderQuery<T, K>): Promise<number>;
|
|
26
25
|
}
|