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.
Files changed (74) hide show
  1. package/db/Database.d.ts +12 -21
  2. package/db/Database.js +25 -35
  3. package/db/Pagination.d.ts +2 -10
  4. package/db/Pagination.js +16 -39
  5. package/db/Write.d.ts +29 -13
  6. package/db/Write.js +42 -17
  7. package/feedback/hydrations.d.ts +5 -5
  8. package/feedback/hydrations.js +5 -5
  9. package/firestore/client/FirestoreClientProvider.d.ts +7 -3
  10. package/firestore/client/FirestoreClientProvider.js +47 -38
  11. package/firestore/lite/FirestoreLiteProvider.d.ts +7 -3
  12. package/firestore/lite/FirestoreLiteProvider.js +42 -40
  13. package/firestore/server/FirestoreServerProvider.d.ts +7 -3
  14. package/firestore/server/FirestoreServerProvider.js +54 -52
  15. package/index.d.ts +4 -4
  16. package/index.js +4 -4
  17. package/package.json +3 -1
  18. package/provider/CacheProvider.d.ts +7 -3
  19. package/provider/CacheProvider.js +26 -14
  20. package/provider/MemoryProvider.d.ts +7 -3
  21. package/provider/MemoryProvider.js +31 -13
  22. package/provider/Provider.d.ts +44 -19
  23. package/provider/ThroughProvider.d.ts +7 -3
  24. package/provider/ThroughProvider.js +16 -4
  25. package/provider/ValidationProvider.d.ts +5 -3
  26. package/provider/ValidationProvider.js +11 -9
  27. package/query/Filter.js +2 -2
  28. package/query/Filters.js +2 -2
  29. package/stream/ArrayState.d.ts +1 -1
  30. package/stream/ArrayState.js +1 -1
  31. package/stream/DataState.d.ts +2 -2
  32. package/stream/State.d.ts +2 -2
  33. package/stream/State.js +3 -3
  34. package/update/DataUpdate.d.ts +25 -0
  35. package/update/DataUpdate.js +25 -0
  36. package/update/EntriesUpdate.d.ts +29 -0
  37. package/update/EntriesUpdate.js +45 -0
  38. package/update/Increment.d.ts +14 -0
  39. package/{transform/IncrementTransform.js → update/Increment.js} +6 -4
  40. package/update/ItemsUpdate.d.ts +21 -0
  41. package/update/ItemsUpdate.js +34 -0
  42. package/update/Update.d.ts +9 -0
  43. package/update/Update.js +6 -0
  44. package/update/hydrations.d.ts +11 -0
  45. package/update/hydrations.js +12 -0
  46. package/update/index.d.ts +7 -0
  47. package/update/index.js +7 -0
  48. package/update/util.d.ts +7 -0
  49. package/update/util.js +42 -0
  50. package/util/filter.d.ts +4 -5
  51. package/util/filter.js +6 -7
  52. package/util/object.d.ts +2 -2
  53. package/util/object.js +2 -2
  54. package/util/transform.d.ts +15 -31
  55. package/util/transform.js +25 -24
  56. package/transform/AddEntriesTransform.d.ts +0 -10
  57. package/transform/AddEntriesTransform.js +0 -16
  58. package/transform/AddItemsTransform.d.ts +0 -10
  59. package/transform/AddItemsTransform.js +0 -16
  60. package/transform/DataTransform.d.ts +0 -24
  61. package/transform/DataTransform.js +0 -24
  62. package/transform/IncrementTransform.d.ts +0 -12
  63. package/transform/RemoveEntriesTransform.d.ts +0 -10
  64. package/transform/RemoveEntriesTransform.js +0 -16
  65. package/transform/RemoveItemsTransform.d.ts +0 -10
  66. package/transform/RemoveItemsTransform.js +0 -16
  67. package/transform/Transform.d.ts +0 -9
  68. package/transform/Transform.js +0 -6
  69. package/transform/hydrations.d.ts +0 -15
  70. package/transform/hydrations.js +0 -16
  71. package/transform/index.d.ts +0 -9
  72. package/transform/index.js +0 -9
  73. package/transform/util.d.ts +0 -7
  74. 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, Transform, AddItemsTransform, AddEntriesTransform, IncrementTransform, RemoveItemsTransform, RemoveEntriesTransform, AssertionError, DataTransform, } from "../../index.js";
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 `Transform` instances into corresponding Firestore `FieldValue` instances. */
48
- function getFieldValues(transform) {
49
- if (transform instanceof DataTransform)
50
- return Object.fromEntries(yieldFieldValues(transform));
51
- throw new AssertionError("Unsupported transform", 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(transforms, prefix = "") {
54
- for (const [key, transform] of transforms) {
55
- if (!(transform instanceof Transform))
56
- yield [`${prefix}${key}`, transform];
57
- if (transform instanceof IncrementTransform)
58
- yield [`${prefix}${key}`, firestoreIncrement(transform.amount)];
59
- else if (transform instanceof AddItemsTransform)
60
- yield [`${prefix}${key}`, firestoreArrayUnion(...transform)];
61
- else if (transform instanceof RemoveItemsTransform)
62
- yield [`${prefix}${key}`, firestoreArrayRemove(...transform)];
63
- else if (transform instanceof AddEntriesTransform)
64
- for (const [k, v] of transform)
65
- yield [`${prefix}${key}.${k}`, v];
66
- else if (transform instanceof RemoveEntriesTransform)
67
- for (const k of transform)
68
- yield [`${prefix}${key}.${k}`, firestoreDeleteField()];
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", 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 write(ref, value) {
98
- if (value instanceof Transform)
99
- await updateDoc(getDocument(this.firestore, ref), getFieldValues(value));
100
- else if (value)
101
- await setDoc(getDocument(this.firestore, ref), value);
102
- else
103
- await deleteDoc(getDocument(this.firestore, ref));
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 writeQuery(ref, value) {
110
+ async setQuery(ref, data) {
112
111
  const snapshot = await getDocs(getQuery(this.firestore, ref));
113
- const updates = value instanceof Transform && getFieldValues(value);
114
- if (updates)
115
- await Promise.all(snapshot.docs.map(s => updateDoc(s.ref, updates)));
116
- else if (value)
117
- await Promise.all(snapshot.docs.map(s => setDoc(s.ref, value)));
118
- else
119
- await Promise.all(snapshot.docs.map(s => deleteDoc(s.ref)));
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, Transform, Data, AsynchronousProvider, Entry, Results, Unsubscriber } from "../../index.js";
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
- write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): Promise<void>;
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
- writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): Promise<void>;
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, Transform, IncrementTransform, AddItemsTransform, RemoveItemsTransform, AddEntriesTransform, RemoveEntriesTransform, DataTransform, AssertionError, } from "../../index.js";
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 a `Transform` instances into corresponding Firestore `FieldValue` instances. */
48
- function getFieldValues(transform) {
49
- if (transform instanceof DataTransform)
50
- return Object.fromEntries(yieldFieldValues(transform));
51
- throw new AssertionError("Unsupported transform", 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(transforms, prefix = "") {
54
- for (const [key, transform] of transforms) {
55
- if (!(transform instanceof Transform))
56
- yield [`${prefix}${key}`, transform];
57
- if (transform instanceof IncrementTransform)
58
- yield [`${prefix}${key}`, FieldValue.increment(transform.amount)];
59
- else if (transform instanceof AddItemsTransform)
60
- yield [`${prefix}${key}`, FieldValue.arrayUnion(...transform)];
61
- else if (transform instanceof RemoveItemsTransform)
62
- yield [`${prefix}${key}`, FieldValue.arrayRemove(...transform)];
63
- else if (transform instanceof AddEntriesTransform)
64
- for (const [k, v] of transform)
65
- yield [`${prefix}${key}.${k}`, v];
66
- else if (transform instanceof RemoveEntriesTransform)
67
- for (const k of transform)
68
- yield [`${prefix}${key}.${k}`, FieldValue.delete()];
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", 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 write(ref, value) {
94
- if (value instanceof Transform)
95
- await getDocument(this.firestore, ref).update(getFieldValues(value));
96
- else if (value)
97
- await getDocument(this.firestore, ref).set(value);
98
- else
99
- await getDocument(this.firestore, ref).delete();
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 writeQuery(ref, value) {
108
- const writer = this.firestore.bulkWriter();
109
- const query = getQuery(this.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.
110
- const updates = value instanceof Transform ? getFieldValues(value) : undefined;
111
- let current = query;
112
- while (current) {
113
- const snapshot = await current.get();
114
- if (updates)
115
- for (const s of snapshot.docs)
116
- void writer.update(s.ref, updates);
117
- else if (value)
118
- for (const s of snapshot.docs)
119
- void writer.set(s.ref, value);
120
- else
121
- for (const s of snapshot.docs)
122
- void writer.delete(s.ref);
123
- current = snapshot.size >= BATCH_SIZE && query.startAfter(snapshot.docs.pop()).select();
124
- void writer.flush();
125
- }
126
- await writer.close();
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 "./transform/index.js";
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 "./transform/index.js";
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.23.2",
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 { Transform } from "../transform/index.js";
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
- write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): Promise<void>;
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
- writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): Promise<void>;
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.write(ref, result);
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.write(ref.doc(id), data);
39
+ this.cache.set(ref.doc(id), data);
41
40
  return id;
42
41
  }
43
- async write(ref, value) {
44
- await super.write(ref, value);
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
- if (value instanceof Transform)
48
- this.cache.writeQuery(ref.optional, value);
49
- else
50
- this.cache.write(ref, value);
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.write(ref.doc(id), undefined);
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.write(ref.doc(id), data);
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 writeQuery(ref, value) {
78
- await super.writeQuery(ref, value);
79
- this.cache.writeQuery(ref, value);
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 { Transform } from "../transform/index.js";
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
- write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): void;
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
- writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): void;
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
- write(ref, value) {
41
+ set(ref, data) {
43
42
  const table = this._table(ref);
44
43
  const id = ref.id;
45
- if (value instanceof Transform) {
46
- const existing = table.data.get(id);
47
- if (!existing)
48
- throw new DocumentRequiredError(ref);
49
- table.write(id, value.transform(existing));
50
- }
51
- else {
52
- table.write(id, value);
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
- writeQuery(ref, value) {
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, value instanceof Transform ? value.transform(existing) : value);
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() {
@@ -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 { Transform } from "../transform/index.js";
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
- * Write to a document.
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 value Value to set the document to.
40
- * - If an object is provided, set the document to the value.
41
- * - If a `Transform` instance is provided, ensure the document exists and transform it.
42
- * - If `undefined` is provided, delete the document.
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
- * @return Nothing (possibly promised).
45
- * @throws Error If a `Transform` was provided but the document does not exist (ideally a `RequiredError` but may be provider-specific).
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 write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): void | PromiseLike<void>;
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
- * Write to all matching documents.
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
- * - If an object is provided, set the document to the value.
71
- * - If a `Transform` instance is provided, ensure the document exists and transform it.
72
- * - If `undefined` is provided, delete the document.
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
- * @return Nothing (possibly promised).
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 writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): void | PromiseLike<void>;
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
- write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): void;
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
- writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): void;
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
- write<T extends Data>(ref: DataDocument<T>, value: T | Transform<T> | undefined): PromiseLike<void>;
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
- writeQuery<T extends Data>(ref: DataQuery<T>, value: T | Transform<T> | undefined): PromiseLike<void>;
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
  }