shelving 1.23.2 → 1.26.1
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 +12 -21
- package/db/Database.js +25 -35
- package/db/Pagination.d.ts +2 -10
- package/db/Pagination.js +16 -39
- package/db/Write.d.ts +29 -13
- package/db/Write.js +42 -17
- package/feedback/hydrations.d.ts +5 -5
- package/feedback/hydrations.js +5 -5
- package/firestore/client/FirestoreClientProvider.d.ts +7 -3
- package/firestore/client/FirestoreClientProvider.js +47 -38
- package/firestore/lite/FirestoreLiteProvider.d.ts +7 -3
- package/firestore/lite/FirestoreLiteProvider.js +42 -40
- package/firestore/server/FirestoreServerProvider.d.ts +7 -3
- package/firestore/server/FirestoreServerProvider.js +54 -52
- package/index.d.ts +4 -4
- package/index.js +4 -4
- package/package.json +3 -1
- package/provider/CacheProvider.d.ts +7 -3
- package/provider/CacheProvider.js +26 -14
- package/provider/MemoryProvider.d.ts +7 -3
- package/provider/MemoryProvider.js +31 -13
- package/provider/Provider.d.ts +44 -19
- package/provider/ThroughProvider.d.ts +7 -3
- package/provider/ThroughProvider.js +16 -4
- package/provider/ValidationProvider.d.ts +5 -3
- package/provider/ValidationProvider.js +11 -9
- package/query/Filter.js +2 -2
- package/query/Filters.js +2 -2
- package/stream/ArrayState.d.ts +1 -1
- package/stream/ArrayState.js +1 -1
- package/stream/DataState.d.ts +2 -2
- package/stream/State.d.ts +2 -2
- package/stream/State.js +3 -3
- package/update/DataUpdate.d.ts +25 -0
- package/update/DataUpdate.js +25 -0
- package/update/EntriesUpdate.d.ts +29 -0
- package/update/EntriesUpdate.js +45 -0
- package/update/Increment.d.ts +14 -0
- package/{transform/IncrementTransform.js → update/Increment.js} +6 -4
- package/update/ItemsUpdate.d.ts +21 -0
- package/update/ItemsUpdate.js +34 -0
- package/update/Update.d.ts +9 -0
- package/update/Update.js +6 -0
- package/update/hydrations.d.ts +11 -0
- package/update/hydrations.js +12 -0
- package/update/index.d.ts +7 -0
- package/update/index.js +7 -0
- package/update/util.d.ts +7 -0
- package/update/util.js +42 -0
- package/util/filter.d.ts +4 -5
- package/util/filter.js +6 -7
- package/util/object.d.ts +2 -2
- package/util/object.js +2 -2
- package/util/transform.d.ts +15 -31
- package/util/transform.js +25 -24
- package/transform/AddEntriesTransform.d.ts +0 -10
- package/transform/AddEntriesTransform.js +0 -16
- package/transform/AddItemsTransform.d.ts +0 -10
- package/transform/AddItemsTransform.js +0 -16
- package/transform/DataTransform.d.ts +0 -24
- package/transform/DataTransform.js +0 -24
- package/transform/IncrementTransform.d.ts +0 -12
- package/transform/RemoveEntriesTransform.d.ts +0 -10
- package/transform/RemoveEntriesTransform.js +0 -16
- package/transform/RemoveItemsTransform.d.ts +0 -10
- package/transform/RemoveItemsTransform.js +0 -16
- package/transform/Transform.d.ts +0 -9
- package/transform/Transform.js +0 -6
- package/transform/hydrations.d.ts +0 -15
- package/transform/hydrations.js +0 -16
- package/transform/index.d.ts +0 -9
- package/transform/index.js +0 -9
- package/transform/util.d.ts +0 -7
- package/transform/util.js +0 -42
|
@@ -1,5 +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
|
-
import { Provider,
|
|
2
|
+
import { Provider, Update, EntriesUpdate, Increment, AssertionError, DataUpdate, ItemsUpdate, UnsupportedError, } from "../../index.js";
|
|
3
3
|
// Constants.
|
|
4
4
|
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
5
5
|
const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
@@ -44,32 +44,30 @@ function* getResults(snapshot) {
|
|
|
44
44
|
for (const s of snapshot.docs)
|
|
45
45
|
yield [s.id, s.data()];
|
|
46
46
|
}
|
|
47
|
-
/** Convert `
|
|
48
|
-
function getFieldValues(
|
|
49
|
-
if (
|
|
50
|
-
return Object.fromEntries(yieldFieldValues(
|
|
51
|
-
throw new AssertionError("Unsupported transform",
|
|
47
|
+
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
48
|
+
function getFieldValues(update) {
|
|
49
|
+
if (update instanceof DataUpdate)
|
|
50
|
+
return Object.fromEntries(yieldFieldValues(update));
|
|
51
|
+
throw new AssertionError("Unsupported transform", update);
|
|
52
52
|
}
|
|
53
|
-
function* yieldFieldValues(
|
|
54
|
-
for (const [key,
|
|
55
|
-
if (!(
|
|
56
|
-
yield [`${prefix}${key}`,
|
|
57
|
-
if (
|
|
58
|
-
yield [`${prefix}${key}`, firestoreIncrement(
|
|
59
|
-
else if (
|
|
60
|
-
yield
|
|
61
|
-
else if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
yield [`${prefix}${key}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
else if (transform instanceof DataTransform)
|
|
70
|
-
yield* yieldFieldValues(transform, `${prefix}${key}.`);
|
|
53
|
+
function* yieldFieldValues(updates, prefix = "") {
|
|
54
|
+
for (const [key, update] of updates) {
|
|
55
|
+
if (!(update instanceof Update))
|
|
56
|
+
yield [`${prefix}${key}`, update !== undefined ? update : firestoreDeleteField()];
|
|
57
|
+
else if (update instanceof Increment)
|
|
58
|
+
yield [`${prefix}${key}`, firestoreIncrement(update.amount)];
|
|
59
|
+
else if (update instanceof DataUpdate || update instanceof EntriesUpdate)
|
|
60
|
+
yield* yieldFieldValues(update, `${prefix}${key}.`);
|
|
61
|
+
else if (update instanceof ItemsUpdate) {
|
|
62
|
+
if (update.adds.length && update.deletes.length)
|
|
63
|
+
throw new UnsupportedError("Cannot add/delete array items in one update");
|
|
64
|
+
if (update.adds.length)
|
|
65
|
+
yield [`${prefix}${key}`, firestoreArrayUnion(...update.adds)];
|
|
66
|
+
else if (update.deletes.length)
|
|
67
|
+
yield [`${prefix}${key}`, firestoreArrayRemove(...update.deletes)];
|
|
68
|
+
}
|
|
71
69
|
else
|
|
72
|
-
throw new AssertionError("Unsupported transform",
|
|
70
|
+
throw new AssertionError("Unsupported transform", update);
|
|
73
71
|
}
|
|
74
72
|
}
|
|
75
73
|
/**
|
|
@@ -94,13 +92,14 @@ export class FirestoreClientProvider extends Provider {
|
|
|
94
92
|
const reference = await addDoc(getCollection(this.firestore, ref), data); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
95
93
|
return reference.id;
|
|
96
94
|
}
|
|
97
|
-
async
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
95
|
+
async set(ref, data) {
|
|
96
|
+
await setDoc(getDocument(this.firestore, ref), data);
|
|
97
|
+
}
|
|
98
|
+
async update(ref, updates) {
|
|
99
|
+
await updateDoc(getDocument(this.firestore, ref), getFieldValues(updates));
|
|
100
|
+
}
|
|
101
|
+
async delete(ref) {
|
|
102
|
+
await deleteDoc(getDocument(this.firestore, ref));
|
|
104
103
|
}
|
|
105
104
|
async getQuery(ref) {
|
|
106
105
|
return getResults(await getDocs(getQuery(this.firestore, ref)));
|
|
@@ -108,14 +107,17 @@ export class FirestoreClientProvider extends Provider {
|
|
|
108
107
|
subscribeQuery() {
|
|
109
108
|
throw new Error("FirestoreLiteProvider does not support realtime subscriptions");
|
|
110
109
|
}
|
|
111
|
-
async
|
|
110
|
+
async setQuery(ref, data) {
|
|
112
111
|
const snapshot = await getDocs(getQuery(this.firestore, ref));
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
112
|
+
await Promise.all(snapshot.docs.map(s => setDoc(s.ref, data)));
|
|
113
|
+
}
|
|
114
|
+
async updateQuery(ref, updates) {
|
|
115
|
+
const snapshot = await getDocs(getQuery(this.firestore, ref));
|
|
116
|
+
const fieldValues = getFieldValues(updates);
|
|
117
|
+
await Promise.all(snapshot.docs.map(s => updateDoc(s.ref, fieldValues)));
|
|
118
|
+
}
|
|
119
|
+
async deleteQuery(ref) {
|
|
120
|
+
const snapshot = await getDocs(getQuery(this.firestore, ref));
|
|
121
|
+
await Promise.all(snapshot.docs.map(s => deleteDoc(s.ref)));
|
|
120
122
|
}
|
|
121
123
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Firestore } from "@google-cloud/firestore";
|
|
2
|
-
import { Provider, DataDocument, DataQuery, Observer, Result,
|
|
2
|
+
import { Provider, DataDocument, DataQuery, Observer, Result, Update, Data, AsynchronousProvider, Entry, Results, Unsubscriber } from "../../index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Firestore server database provider.
|
|
5
5
|
* - Works with the Firebase Admin SDK for Node.JS
|
|
@@ -10,8 +10,12 @@ export declare class FirestoreServerProvider extends Provider implements Asynchr
|
|
|
10
10
|
get<T extends Data>(ref: DataDocument<T>): Promise<Result<T>>;
|
|
11
11
|
subscribe<T extends Data>(ref: DataDocument<T>, observer: Observer<Result<T>>): Unsubscriber;
|
|
12
12
|
add<T extends Data>(ref: DataQuery<T>, data: T): Promise<string>;
|
|
13
|
-
|
|
13
|
+
set<T extends Data>(ref: DataDocument<T>, data: T): Promise<void>;
|
|
14
|
+
update<T extends Data>(ref: DataDocument<T>, updates: Update<T>): Promise<void>;
|
|
15
|
+
delete<T extends Data>(ref: DataDocument<T>): Promise<void>;
|
|
14
16
|
getQuery<T extends Data>(ref: DataQuery<T>): Promise<Iterable<Entry<T>>>;
|
|
15
17
|
subscribeQuery<T extends Data>(ref: DataQuery<T>, observer: Observer<Results<T>>): Unsubscriber;
|
|
16
|
-
|
|
18
|
+
setQuery<T extends Data>(ref: DataQuery<T>, data: T | Update<T> | undefined): Promise<void>;
|
|
19
|
+
updateQuery<T extends Data>(ref: DataQuery<T>, updates: Update<T>): Promise<void>;
|
|
20
|
+
deleteQuery<T extends Data>(ref: DataQuery<T>): Promise<void>;
|
|
17
21
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Firestore, FieldValue } from "@google-cloud/firestore";
|
|
2
|
-
import { Provider, dispatchNext, dispatchError,
|
|
2
|
+
import { Provider, dispatchNext, dispatchError, Update, Increment, DataUpdate, AssertionError, ItemsUpdate, UnsupportedError, EntriesUpdate, } from "../../index.js";
|
|
3
3
|
// Constants.
|
|
4
4
|
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
5
5
|
const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
@@ -44,32 +44,30 @@ function* getResults(snapshot) {
|
|
|
44
44
|
for (const s of snapshot.docs)
|
|
45
45
|
yield [s.id, s.data()];
|
|
46
46
|
}
|
|
47
|
-
/** Convert
|
|
48
|
-
function getFieldValues(
|
|
49
|
-
if (
|
|
50
|
-
return Object.fromEntries(yieldFieldValues(
|
|
51
|
-
throw new AssertionError("Unsupported transform",
|
|
47
|
+
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
48
|
+
function getFieldValues(update) {
|
|
49
|
+
if (update instanceof DataUpdate)
|
|
50
|
+
return Object.fromEntries(yieldFieldValues(update));
|
|
51
|
+
throw new AssertionError("Unsupported transform", update);
|
|
52
52
|
}
|
|
53
|
-
function* yieldFieldValues(
|
|
54
|
-
for (const [key,
|
|
55
|
-
if (!(
|
|
56
|
-
yield [`${prefix}${key}`,
|
|
57
|
-
if (
|
|
58
|
-
yield [`${prefix}${key}`, FieldValue.increment(
|
|
59
|
-
else if (
|
|
60
|
-
yield
|
|
61
|
-
else if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
yield [`${prefix}${key}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
else if (transform instanceof DataTransform)
|
|
70
|
-
yield* yieldFieldValues(transform, `${prefix}${key}.`);
|
|
53
|
+
function* yieldFieldValues(updates, prefix = "") {
|
|
54
|
+
for (const [key, update] of updates) {
|
|
55
|
+
if (!(update instanceof Update))
|
|
56
|
+
yield [`${prefix}${key}`, update !== undefined ? update : FieldValue.delete()];
|
|
57
|
+
if (update instanceof Increment)
|
|
58
|
+
yield [`${prefix}${key}`, FieldValue.increment(update.amount)];
|
|
59
|
+
else if (update instanceof DataUpdate || update instanceof EntriesUpdate)
|
|
60
|
+
yield* yieldFieldValues(update, `${prefix}${key}.`);
|
|
61
|
+
else if (update instanceof ItemsUpdate) {
|
|
62
|
+
if (update.adds.length && update.deletes.length)
|
|
63
|
+
throw new UnsupportedError("Cannot add/delete array items in one update");
|
|
64
|
+
if (update.adds.length)
|
|
65
|
+
yield [`${prefix}${key}`, FieldValue.arrayUnion(...update.adds)];
|
|
66
|
+
else if (update.deletes.length)
|
|
67
|
+
yield [`${prefix}${key}`, FieldValue.arrayRemove(...update.deletes)];
|
|
68
|
+
}
|
|
71
69
|
else
|
|
72
|
-
throw new AssertionError("Unsupported transform",
|
|
70
|
+
throw new AssertionError("Unsupported transform", update);
|
|
73
71
|
}
|
|
74
72
|
}
|
|
75
73
|
/**
|
|
@@ -90,13 +88,14 @@ export class FirestoreServerProvider extends Provider {
|
|
|
90
88
|
async add(ref, data) {
|
|
91
89
|
return (await getCollection(this.firestore, ref).add(data)).id;
|
|
92
90
|
}
|
|
93
|
-
async
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
async set(ref, data) {
|
|
92
|
+
await getDocument(this.firestore, ref).set(data);
|
|
93
|
+
}
|
|
94
|
+
async update(ref, updates) {
|
|
95
|
+
await getDocument(this.firestore, ref).update(getFieldValues(updates));
|
|
96
|
+
}
|
|
97
|
+
async delete(ref) {
|
|
98
|
+
await getDocument(this.firestore, ref).delete();
|
|
100
99
|
}
|
|
101
100
|
async getQuery(ref) {
|
|
102
101
|
return getResults(await getQuery(this.firestore, ref).get());
|
|
@@ -104,26 +103,29 @@ export class FirestoreServerProvider extends Provider {
|
|
|
104
103
|
subscribeQuery(ref, observer) {
|
|
105
104
|
return getQuery(this.firestore, ref).onSnapshot(snapshot => dispatchNext(observer, getResults(snapshot)), thrown => dispatchError(observer, thrown));
|
|
106
105
|
}
|
|
107
|
-
async
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
106
|
+
async setQuery(ref, data) {
|
|
107
|
+
await bulkWrite(this.firestore, ref, (w, s) => void w.set(s.ref, data));
|
|
108
|
+
}
|
|
109
|
+
async updateQuery(ref, updates) {
|
|
110
|
+
const fieldValues = getFieldValues(updates);
|
|
111
|
+
await bulkWrite(this.firestore, ref, (w, s) => void w.update(s.ref, fieldValues));
|
|
112
|
+
}
|
|
113
|
+
async deleteQuery(ref) {
|
|
114
|
+
await bulkWrite(this.firestore, ref, (w, s) => void w.delete(s.ref));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** Perform a bulk update on a set of documents using a `BulkWriter` */
|
|
118
|
+
async function bulkWrite(firestore, ref, callback) {
|
|
119
|
+
const writer = firestore.bulkWriter();
|
|
120
|
+
const query = getQuery(firestore, ref).limit(BATCH_SIZE).select(); // `select()` turs the query into a field mask query (with no field masks) which saves data transfer and memory.
|
|
121
|
+
let current = query;
|
|
122
|
+
while (current) {
|
|
123
|
+
const snapshot = await current.get();
|
|
124
|
+
for (const s of snapshot.docs)
|
|
125
|
+
callback(writer, s);
|
|
126
|
+
current = snapshot.size >= BATCH_SIZE && query.startAfter(snapshot.docs.pop()).select();
|
|
127
|
+
void writer.flush();
|
|
127
128
|
}
|
|
129
|
+
await writer.close();
|
|
128
130
|
}
|
|
129
131
|
const BATCH_SIZE = 1000;
|
package/index.d.ts
CHANGED
|
@@ -8,9 +8,9 @@ export * from "./db/index.js";
|
|
|
8
8
|
export * from "./provider/index.js";
|
|
9
9
|
export * from "./query/index.js";
|
|
10
10
|
export * from "./api/index.js";
|
|
11
|
-
export * from "./util/index.js";
|
|
12
|
-
export * from "./stream/index.js";
|
|
13
|
-
export * from "./feedback/index.js";
|
|
14
11
|
export * from "./error/index.js";
|
|
15
|
-
export * from "./
|
|
12
|
+
export * from "./feedback/index.js";
|
|
16
13
|
export * from "./markup/index.js";
|
|
14
|
+
export * from "./stream/index.js";
|
|
15
|
+
export * from "./update/index.js";
|
|
16
|
+
export * from "./util/index.js";
|
package/index.js
CHANGED
|
@@ -10,12 +10,12 @@ export * from "./provider/index.js";
|
|
|
10
10
|
export * from "./query/index.js";
|
|
11
11
|
export * from "./api/index.js";
|
|
12
12
|
// Utilities.
|
|
13
|
-
export * from "./util/index.js";
|
|
14
|
-
export * from "./stream/index.js";
|
|
15
|
-
export * from "./feedback/index.js";
|
|
16
13
|
export * from "./error/index.js";
|
|
17
|
-
export * from "./
|
|
14
|
+
export * from "./feedback/index.js";
|
|
18
15
|
export * from "./markup/index.js";
|
|
16
|
+
export * from "./stream/index.js";
|
|
17
|
+
export * from "./update/index.js";
|
|
18
|
+
export * from "./util/index.js";
|
|
19
19
|
// Integrations.
|
|
20
20
|
// export * from "./react/index.js"; // Not exported.
|
|
21
21
|
// Testing.
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"state-management",
|
|
12
12
|
"query-builder"
|
|
13
13
|
],
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.26.1",
|
|
15
15
|
"repository": "https://github.com/dhoulb/shelving",
|
|
16
16
|
"author": "Dave Houlbrooke <dave@shax.com>",
|
|
17
17
|
"license": "0BSD",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
".": "./index.js",
|
|
24
24
|
"./api": "./api/index.js",
|
|
25
25
|
"./db": "./db/index.js",
|
|
26
|
+
"./error": "./error/index.js",
|
|
26
27
|
"./feedback": "./feedback/index.js",
|
|
27
28
|
"./firestore/client": "./firestore-client/index.js",
|
|
28
29
|
"./firestore/lite": "./firestore-lite/index.js",
|
|
@@ -34,6 +35,7 @@
|
|
|
34
35
|
"./schema": "./schema/index.js",
|
|
35
36
|
"./stream": "./stream/index.js",
|
|
36
37
|
"./test": "./test/index.js",
|
|
38
|
+
"./update": "./update/index.js",
|
|
37
39
|
"./util": "./util/index.js"
|
|
38
40
|
},
|
|
39
41
|
"sideEffects": false,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DataDocument, DataQuery } from "../db/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Update } from "../update/index.js";
|
|
3
3
|
import { Result, Unsubscriber, Observer, Results, Data } from "../util/index.js";
|
|
4
4
|
import type { Provider, AsynchronousProvider } from "./Provider.js";
|
|
5
5
|
import { MemoryProvider } from "./MemoryProvider.js";
|
|
@@ -20,12 +20,16 @@ export declare class CacheProvider extends ThroughProvider implements Asynchrono
|
|
|
20
20
|
get<T extends Data>(ref: DataDocument<T>): Promise<Result<T>>;
|
|
21
21
|
subscribe<T extends Data>(ref: DataDocument<T>, observer: Observer<Result<T>>): Unsubscriber;
|
|
22
22
|
add<T extends Data>(ref: DataQuery<T>, data: T): Promise<string>;
|
|
23
|
-
|
|
23
|
+
set<T extends Data>(ref: DataDocument<T>, data: T): Promise<void>;
|
|
24
|
+
update<T extends Data>(ref: DataDocument<T>, updates: Update<T>): Promise<void>;
|
|
25
|
+
delete<T extends Data>(ref: DataDocument<T>): Promise<void>;
|
|
24
26
|
/** Cache a set of document results. */
|
|
25
27
|
private _cacheResults;
|
|
26
28
|
getQuery<T extends Data>(ref: DataQuery<T>): Promise<Results<T>>;
|
|
27
29
|
subscribeQuery<T extends Data>(ref: DataQuery<T>, observer: Observer<Results<T>>): Unsubscriber;
|
|
28
|
-
|
|
30
|
+
setQuery<T extends Data>(ref: DataQuery<T>, data: T): Promise<void>;
|
|
31
|
+
updateQuery<T extends Data>(ref: DataQuery<T>, updates: Update<T>): Promise<void>;
|
|
32
|
+
deleteQuery<T extends Data>(ref: DataQuery<T>): Promise<void>;
|
|
29
33
|
/** Reset this provider and clear all data. */
|
|
30
34
|
reset(): void;
|
|
31
35
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Transform } from "../transform/index.js";
|
|
2
1
|
import { TransformObserver } from "../util/index.js";
|
|
3
2
|
import { MemoryProvider } from "./MemoryProvider.js";
|
|
4
3
|
import { ThroughProvider } from "./ThroughProvider.js";
|
|
@@ -23,7 +22,7 @@ export class CacheProvider extends ThroughProvider {
|
|
|
23
22
|
}
|
|
24
23
|
/** Cache an individual document result. */
|
|
25
24
|
_cacheResult(ref, result) {
|
|
26
|
-
this.cache.
|
|
25
|
+
result ? this.cache.set(ref, result) : this.cache.delete(ref);
|
|
27
26
|
this._times[ref.toString()] = Date.now();
|
|
28
27
|
return result;
|
|
29
28
|
}
|
|
@@ -37,17 +36,22 @@ export class CacheProvider extends ThroughProvider {
|
|
|
37
36
|
}
|
|
38
37
|
async add(ref, data) {
|
|
39
38
|
const id = await super.add(ref, data);
|
|
40
|
-
this.cache.
|
|
39
|
+
this.cache.set(ref.doc(id), data);
|
|
41
40
|
return id;
|
|
42
41
|
}
|
|
43
|
-
async
|
|
44
|
-
await super.
|
|
42
|
+
async set(ref, data) {
|
|
43
|
+
await super.set(ref, data);
|
|
44
|
+
this.cache.set(ref, data);
|
|
45
|
+
}
|
|
46
|
+
async update(ref, updates) {
|
|
47
|
+
await super.update(ref, updates);
|
|
45
48
|
// Update the document in the cache if it exists using `updateDocuments()` and an `id` query.
|
|
46
49
|
// Using `updateDocument()` would throw `RequiredError` if the document didn't exist.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
this.cache.updateQuery(ref.optional, updates);
|
|
51
|
+
}
|
|
52
|
+
async delete(ref) {
|
|
53
|
+
await super.delete(ref);
|
|
54
|
+
this.cache.delete(ref);
|
|
51
55
|
}
|
|
52
56
|
/** Cache a set of document results. */
|
|
53
57
|
*_cacheResults(ref, results) {
|
|
@@ -57,10 +61,10 @@ export class CacheProvider extends ThroughProvider {
|
|
|
57
61
|
if (!ref.limit)
|
|
58
62
|
for (const id of Object.keys(this.cache.getQuery(ref)))
|
|
59
63
|
if (!(id in results))
|
|
60
|
-
this.cache.
|
|
64
|
+
this.cache.delete(ref.doc(id));
|
|
61
65
|
// Save new results to the cache.
|
|
62
66
|
for (const [id, data] of results) {
|
|
63
|
-
this.cache.
|
|
67
|
+
this.cache.set(ref.doc(id), data);
|
|
64
68
|
yield [id, data];
|
|
65
69
|
}
|
|
66
70
|
// Save the last-cached time.
|
|
@@ -74,9 +78,17 @@ export class CacheProvider extends ThroughProvider {
|
|
|
74
78
|
subscribeQuery(ref, observer) {
|
|
75
79
|
return super.subscribeQuery(ref, new TransformObserver(results => this._cacheResults(ref, results), observer));
|
|
76
80
|
}
|
|
77
|
-
async
|
|
78
|
-
await super.
|
|
79
|
-
this.cache.
|
|
81
|
+
async setQuery(ref, data) {
|
|
82
|
+
await super.setQuery(ref, data);
|
|
83
|
+
this.cache.setQuery(ref, data);
|
|
84
|
+
}
|
|
85
|
+
async updateQuery(ref, updates) {
|
|
86
|
+
await super.updateQuery(ref, updates);
|
|
87
|
+
this.cache.updateQuery(ref, updates);
|
|
88
|
+
}
|
|
89
|
+
async deleteQuery(ref) {
|
|
90
|
+
await super.deleteQuery(ref);
|
|
91
|
+
this.cache.deleteQuery(ref);
|
|
80
92
|
}
|
|
81
93
|
/** Reset this provider and clear all data. */
|
|
82
94
|
reset() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Data, Result, Results, Unsubscriber, Observer } from "../util/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Update } from "../update/index.js";
|
|
3
3
|
import { DataQuery, DataDocument } from "../db/index.js";
|
|
4
4
|
import { Provider, SynchronousProvider } from "./Provider.js";
|
|
5
5
|
/**
|
|
@@ -14,10 +14,14 @@ export declare class MemoryProvider extends Provider implements SynchronousProvi
|
|
|
14
14
|
get<T extends Data>(ref: DataDocument<T>): Result<T>;
|
|
15
15
|
subscribe<T extends Data>(ref: DataDocument<T>, observer: Observer<Result<T>>): Unsubscriber;
|
|
16
16
|
add<T extends Data>(ref: DataQuery<T>, data: T): string;
|
|
17
|
-
|
|
17
|
+
set<T extends Data>(ref: DataDocument<T>, data: T): void;
|
|
18
|
+
update<T extends Data>(ref: DataDocument<T>, updates: Update<T>): void;
|
|
19
|
+
delete<T extends Data>(ref: DataDocument<T>): void;
|
|
18
20
|
getQuery<T extends Data>(ref: DataQuery<T>): Results<T>;
|
|
19
21
|
subscribeQuery<T extends Data>(ref: DataQuery<T>, observer: Observer<Results<T>>): Unsubscriber;
|
|
20
|
-
|
|
22
|
+
setQuery<T extends Data>(ref: DataQuery<T>, data: T): void;
|
|
23
|
+
updateQuery<T extends Data>(ref: DataQuery<T>, updates: Update<T>): void;
|
|
24
|
+
deleteQuery<T extends Data>(ref: DataQuery<T>): void;
|
|
21
25
|
/** Reset this provider and clear all data. */
|
|
22
26
|
reset(): void;
|
|
23
27
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { randomId, dispatchNext, isMapEqual, } from "../util/index.js";
|
|
2
|
-
import { Transform } from "../transform/index.js";
|
|
3
2
|
import { DocumentRequiredError } from "../db/index.js";
|
|
4
3
|
import { Provider } from "./Provider.js";
|
|
5
4
|
/**
|
|
@@ -39,18 +38,23 @@ export class MemoryProvider extends Provider {
|
|
|
39
38
|
table.write(id, data);
|
|
40
39
|
return id;
|
|
41
40
|
}
|
|
42
|
-
|
|
41
|
+
set(ref, data) {
|
|
43
42
|
const table = this._table(ref);
|
|
44
43
|
const id = ref.id;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
table.write(id, data);
|
|
45
|
+
}
|
|
46
|
+
update(ref, updates) {
|
|
47
|
+
const table = this._table(ref);
|
|
48
|
+
const id = ref.id;
|
|
49
|
+
const existing = table.data.get(id);
|
|
50
|
+
if (!existing)
|
|
51
|
+
throw new DocumentRequiredError(ref);
|
|
52
|
+
table.write(id, updates.transform(existing));
|
|
53
|
+
}
|
|
54
|
+
delete(ref) {
|
|
55
|
+
const table = this._table(ref);
|
|
56
|
+
const id = ref.id;
|
|
57
|
+
table.write(id, undefined);
|
|
54
58
|
}
|
|
55
59
|
getQuery(ref) {
|
|
56
60
|
return ref.transform(this._table(ref).data);
|
|
@@ -78,12 +82,26 @@ export class MemoryProvider extends Provider {
|
|
|
78
82
|
}
|
|
79
83
|
});
|
|
80
84
|
}
|
|
81
|
-
|
|
85
|
+
setQuery(ref, data) {
|
|
86
|
+
const table = this._table(ref);
|
|
87
|
+
// If there's a limit set: run the full query.
|
|
88
|
+
// If there's no limit set: only need to run the filtering (more efficient because sort order doesn't matter).
|
|
89
|
+
for (const [id] of ref.limit ? ref.transform(table.data) : ref.filters.transform(table.data))
|
|
90
|
+
table.write(id, data);
|
|
91
|
+
}
|
|
92
|
+
updateQuery(ref, updates) {
|
|
82
93
|
const table = this._table(ref);
|
|
83
94
|
// If there's a limit set: run the full query.
|
|
84
95
|
// If there's no limit set: only need to run the filtering (more efficient because sort order doesn't matter).
|
|
85
96
|
for (const [id, existing] of ref.limit ? ref.transform(table.data) : ref.filters.transform(table.data))
|
|
86
|
-
table.write(id,
|
|
97
|
+
table.write(id, updates.transform(existing));
|
|
98
|
+
}
|
|
99
|
+
deleteQuery(ref) {
|
|
100
|
+
const table = this._table(ref);
|
|
101
|
+
// If there's a limit set: run the full query.
|
|
102
|
+
// If there's no limit set: only need to run the filtering (more efficient because sort order doesn't matter).
|
|
103
|
+
for (const [id] of ref.limit ? ref.transform(table.data) : ref.filters.transform(table.data))
|
|
104
|
+
table.write(id, undefined);
|
|
87
105
|
}
|
|
88
106
|
/** Reset this provider and clear all data. */
|
|
89
107
|
reset() {
|
package/provider/Provider.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Observer, Unsubscriber, Result, Results, Data } from "../util/index.js";
|
|
2
2
|
import type { DataDocument, DataQuery } from "../db/Database.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { Update } from "../update/index.js";
|
|
4
4
|
/** Provides access to data (e.g. IndexedDB, Firebase, or in-memory cache providers). */
|
|
5
5
|
export declare abstract class Provider {
|
|
6
6
|
/**
|
|
@@ -31,20 +31,30 @@ export declare abstract class Provider {
|
|
|
31
31
|
*/
|
|
32
32
|
abstract add<T extends Data>(ref: DataQuery<T>, data: T): string | PromiseLike<string>;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Set the data a document.
|
|
35
35
|
* - If the document exists, set the value of it.
|
|
36
36
|
* - If the document doesn't exist, set it at path.
|
|
37
37
|
*
|
|
38
38
|
* @param ref Document reference specifying which document to set.
|
|
39
|
-
* @param
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
|
|
39
|
+
* @param data Data to set the document to.
|
|
40
|
+
*
|
|
41
|
+
* @throws Error If a `Update` was provided but the document does not exist (ideally a `RequiredError` but may be provider-specific).
|
|
42
|
+
*/
|
|
43
|
+
abstract set<T extends Data>(ref: DataDocument<T>, value: T): void | PromiseLike<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Update the data an existing document.
|
|
46
|
+
*
|
|
47
|
+
* @param ref Document reference specifying which document to update.
|
|
48
|
+
* @param updates Update instance to set the document to.
|
|
43
49
|
*
|
|
44
|
-
* @
|
|
45
|
-
|
|
50
|
+
* @throws Error If the document does not exist (ideally a `RequiredError` but may be provider-specific).
|
|
51
|
+
*/
|
|
52
|
+
abstract update<T extends Data>(ref: DataDocument<T>, updates: Update<T>): void | PromiseLike<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Delete a specified document.
|
|
55
|
+
* @param ref Document reference specifying which document to delete.
|
|
46
56
|
*/
|
|
47
|
-
abstract
|
|
57
|
+
abstract delete<T extends Data>(ref: DataDocument<T>): void | PromiseLike<void>;
|
|
48
58
|
/**
|
|
49
59
|
* Get all matching documents.
|
|
50
60
|
*
|
|
@@ -63,31 +73,46 @@ export declare abstract class Provider {
|
|
|
63
73
|
*/
|
|
64
74
|
abstract subscribeQuery<T extends Data>(ref: DataQuery<T>, observer: Observer<Results<T>>): Unsubscriber;
|
|
65
75
|
/**
|
|
66
|
-
*
|
|
76
|
+
* Set the data of all matching documents.
|
|
67
77
|
*
|
|
68
78
|
* @param ref Documents reference specifying which collection to set.
|
|
69
79
|
* @param value Value to set the document to.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
*/
|
|
81
|
+
abstract setQuery<T extends Data>(ref: DataQuery<T>, data: T): void | PromiseLike<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Update the data of all matching documents.
|
|
73
84
|
*
|
|
74
|
-
* @
|
|
85
|
+
* @param ref Documents reference specifying which collection to set.
|
|
86
|
+
* @param updates Update instance to set the document to.
|
|
87
|
+
*/
|
|
88
|
+
abstract updateQuery<T extends Data>(ref: DataQuery<T>, updates: Update<T>): void | PromiseLike<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Delete all matching documents.
|
|
91
|
+
* @param ref Document reference specifying which document to delete.
|
|
75
92
|
*/
|
|
76
|
-
abstract
|
|
93
|
+
abstract deleteQuery<T extends Data>(ref: DataQuery<T>): void | PromiseLike<void>;
|
|
77
94
|
}
|
|
78
95
|
/** Provider with a fully synchronous interface */
|
|
79
96
|
export interface SynchronousProvider extends Provider {
|
|
80
97
|
get<T extends Data>(ref: DataDocument<T>): Result<T>;
|
|
81
98
|
add<T extends Data>(ref: DataQuery<T>, data: T): string;
|
|
82
|
-
|
|
99
|
+
set<T extends Data>(ref: DataDocument<T>, value: T): void;
|
|
100
|
+
update<T extends Data>(ref: DataDocument<T>, value: Update<T>): void;
|
|
101
|
+
delete<T extends Data>(ref: DataDocument<T>): void;
|
|
83
102
|
getQuery<T extends Data>(ref: DataQuery<T>): Results<T>;
|
|
84
|
-
|
|
103
|
+
setQuery<T extends Data>(ref: DataQuery<T>, value: T): void;
|
|
104
|
+
updateQuery<T extends Data>(ref: DataQuery<T>, updates: Update<T>): void;
|
|
105
|
+
deleteQuery<T extends Data>(ref: DataQuery<T>): void;
|
|
85
106
|
}
|
|
86
107
|
/** Provider with a fully asynchronous interface */
|
|
87
108
|
export interface AsynchronousProvider extends Provider {
|
|
88
109
|
get<T extends Data>(ref: DataDocument<T>): PromiseLike<Result<T>>;
|
|
89
110
|
add<T extends Data>(ref: DataQuery<T>, data: T): PromiseLike<string>;
|
|
90
|
-
|
|
111
|
+
set<T extends Data>(ref: DataDocument<T>, value: T): PromiseLike<void>;
|
|
112
|
+
update<T extends Data>(ref: DataDocument<T>, updates: Update<T>): PromiseLike<void>;
|
|
113
|
+
delete<T extends Data>(ref: DataDocument<T>): PromiseLike<void>;
|
|
91
114
|
getQuery<T extends Data>(ref: DataQuery<T>): PromiseLike<Results<T>>;
|
|
92
|
-
|
|
115
|
+
setQuery<T extends Data>(ref: DataQuery<T>, value: T): PromiseLike<void>;
|
|
116
|
+
updateQuery<T extends Data>(ref: DataQuery<T>, updates: Update<T>): PromiseLike<void>;
|
|
117
|
+
deleteQuery<T extends Data>(ref: DataQuery<T>): PromiseLike<void>;
|
|
93
118
|
}
|