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.
Files changed (104) hide show
  1. package/db/Changes.d.ts +21 -0
  2. package/db/Changes.js +36 -0
  3. package/db/Database.d.ts +30 -19
  4. package/db/Database.js +27 -27
  5. package/db/DatabaseDocument.d.ts +87 -0
  6. package/db/DatabaseDocument.js +91 -0
  7. package/db/DatabaseQuery.d.ts +120 -0
  8. package/db/DatabaseQuery.js +120 -0
  9. package/db/index.d.ts +3 -2
  10. package/db/index.js +3 -2
  11. package/error/ValidationError.js +1 -1
  12. package/feedback/ErrorFeedback.d.ts +1 -1
  13. package/feedback/ErrorFeedback.js +1 -0
  14. package/feedback/Feedback.d.ts +15 -12
  15. package/feedback/Feedback.js +18 -26
  16. package/feedback/InvalidFeedback.d.ts +1 -1
  17. package/feedback/InvalidFeedback.js +1 -0
  18. package/feedback/SuccessFeedback.d.ts +1 -1
  19. package/feedback/SuccessFeedback.js +1 -0
  20. package/feedback/WarningFeedback.d.ts +1 -1
  21. package/feedback/WarningFeedback.js +1 -0
  22. package/firestore/client/FirestoreClientProvider.d.ts +14 -15
  23. package/firestore/client/FirestoreClientProvider.js +48 -46
  24. package/firestore/lite/FirestoreLiteProvider.d.ts +12 -13
  25. package/firestore/lite/FirestoreLiteProvider.js +44 -41
  26. package/firestore/server/FirestoreServerProvider.d.ts +14 -15
  27. package/firestore/server/FirestoreServerProvider.js +44 -42
  28. package/markup/regexp.d.ts +9 -1
  29. package/markup/regexp.js +0 -2
  30. package/markup/rules.d.ts +14 -1
  31. package/markup/rules.js +28 -19
  32. package/package.json +5 -5
  33. package/provider/BatchProvider.d.ts +11 -14
  34. package/provider/BatchProvider.js +29 -41
  35. package/provider/CacheProvider.d.ts +20 -21
  36. package/provider/CacheProvider.js +40 -29
  37. package/provider/DebugProvider.d.ts +36 -16
  38. package/provider/DebugProvider.js +150 -101
  39. package/provider/MemoryProvider.d.ts +19 -19
  40. package/provider/MemoryProvider.js +6 -9
  41. package/provider/Provider.d.ts +47 -50
  42. package/provider/Provider.js +7 -1
  43. package/provider/ThroughProvider.d.ts +38 -28
  44. package/provider/ThroughProvider.js +49 -6
  45. package/provider/ValidationProvider.d.ts +40 -14
  46. package/provider/ValidationProvider.js +84 -29
  47. package/query/Filter.d.ts +7 -3
  48. package/query/Filter.js +59 -37
  49. package/query/Filters.d.ts +5 -12
  50. package/query/Filters.js +10 -10
  51. package/query/Query.d.ts +11 -16
  52. package/query/Query.js +30 -30
  53. package/query/Rules.d.ts +0 -1
  54. package/query/Rules.js +0 -4
  55. package/query/Sort.d.ts +6 -3
  56. package/query/Sort.js +25 -7
  57. package/query/Sorts.d.ts +5 -5
  58. package/query/Sorts.js +9 -6
  59. package/react/useDocument.d.ts +8 -8
  60. package/react/useDocument.js +2 -3
  61. package/react/useQuery.d.ts +9 -13
  62. package/react/useQuery.js +6 -15
  63. package/react/useSubscribe.js +1 -2
  64. package/state/ObjectState.d.ts +2 -2
  65. package/state/State.d.ts +7 -4
  66. package/state/State.js +12 -9
  67. package/test/index.d.ts +2 -0
  68. package/test/util.d.ts +3 -3
  69. package/update/DataUpdate.d.ts +1 -1
  70. package/update/DataUpdate.js +7 -9
  71. package/update/ObjectUpdate.d.ts +2 -2
  72. package/update/ObjectUpdate.js +14 -4
  73. package/util/async.d.ts +14 -35
  74. package/util/async.js +48 -63
  75. package/util/data.d.ts +3 -16
  76. package/util/data.js +0 -4
  77. package/util/diff.d.ts +2 -1
  78. package/util/diff.js +2 -1
  79. package/util/entry.d.ts +14 -26
  80. package/util/entry.js +7 -6
  81. package/util/filter.d.ts +2 -2
  82. package/util/hydrate.d.ts +4 -4
  83. package/util/hydrate.js +29 -12
  84. package/util/index.d.ts +0 -1
  85. package/util/index.js +0 -1
  86. package/util/iterate.d.ts +11 -33
  87. package/util/iterate.js +26 -61
  88. package/util/jsx.d.ts +1 -1
  89. package/util/object.d.ts +1 -8
  90. package/util/object.js +8 -8
  91. package/util/sort.d.ts +2 -4
  92. package/util/sort.js +7 -8
  93. package/util/string.d.ts +15 -7
  94. package/util/string.js +13 -11
  95. package/util/transform.d.ts +5 -5
  96. package/util/transform.js +1 -1
  97. package/util/validate.d.ts +2 -2
  98. package/util/validate.js +16 -22
  99. package/db/Operation.d.ts +0 -79
  100. package/db/Operation.js +0 -129
  101. package/db/Reference.d.ts +0 -151
  102. package/db/Reference.js +0 -216
  103. package/util/constants.d.ts +0 -12
  104. package/util/constants.js +0 -12
@@ -1,4 +1,4 @@
1
- import type { ImmutableObject } from "../util/object.js";
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 declare class Feedback {
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 details: ImmutableObject;
18
- constructor(feedback: string, details?: ImmutableObject);
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` instance? */
27
- export declare const isFeedback: <T extends Feedback>(v: unknown) => v is 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>;
@@ -1,30 +1,22 @@
1
- import { getString } from "../util/string.js";
2
- import { mapObject } from "../util/transform.js";
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, details = {}) {
4
+ constructor(feedback, value) {
16
5
  this.message = feedback;
17
- this.details = details;
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
- const _getMessage = (v) => (isFeedback(v) ? v.message : getString(v));
29
- /** Is an unknown value a `Feedback` instance? */
30
- export const isFeedback = (v) => v instanceof Feedback;
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
  }
@@ -2,3 +2,4 @@ import { ErrorFeedback } from "./ErrorFeedback.js";
2
2
  /** Specific type of `ErrorFeedback` returned from `validate()` when a value is invalid. */
3
3
  export class InvalidFeedback extends ErrorFeedback {
4
4
  }
5
+ InvalidFeedback.prototype.name = "InvalidFeedback";
@@ -1,4 +1,4 @@
1
1
  import { Feedback } from "./Feedback.js";
2
2
  /** Specific type of `Feedback` to indicate success (something went right!). */
3
- export declare class SuccessFeedback extends Feedback {
3
+ export declare class SuccessFeedback<T = unknown> extends Feedback<T> {
4
4
  }
@@ -2,3 +2,4 @@ import { Feedback } from "./Feedback.js";
2
2
  /** Specific type of `Feedback` to indicate success (something went right!). */
3
3
  export class SuccessFeedback extends Feedback {
4
4
  }
5
+ SuccessFeedback.prototype.name = "SuccessFeedback";
@@ -1,4 +1,4 @@
1
1
  import { Feedback } from "./Feedback.js";
2
2
  /** Specific type of `Feedback` to indicate warning (something might go wrong soon). */
3
- export declare class WarningFeedback extends Feedback {
3
+ export declare class WarningFeedback<T = unknown> extends Feedback<T> {
4
4
  }
@@ -2,3 +2,4 @@ import { Feedback } from "./Feedback.js";
2
2
  /** Specific type of `Feedback` to indicate warning (something might go wrong soon). */
3
3
  export class WarningFeedback extends Feedback {
4
4
  }
5
+ WarningFeedback.prototype.name = "WarningFeedback";
@@ -1,9 +1,8 @@
1
1
  import type { Firestore } from "firebase/firestore";
2
- import type { DocumentReference, QueryReference } from "../../db/Reference.js";
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 Provider implements AsynchronousProvider {
13
+ export declare class FirestoreClientProvider<T extends Datas> implements AsyncProvider<T> {
15
14
  readonly firestore: Firestore;
16
15
  constructor(firestore: Firestore);
17
- getDocument<T extends Data>(ref: DocumentReference<T>): Promise<OptionalEntity<T>>;
18
- subscribeDocument<T extends Data>(ref: DocumentReference<T>, observer: Observer<OptionalEntity<T>>): Unsubscribe;
19
- addDocument<T extends Data>(ref: QueryReference<T>, data: T): Promise<string>;
20
- setDocument<T extends Data>(ref: DocumentReference<T>, data: T): Promise<void>;
21
- updateDocument<T extends Data>(ref: DocumentReference<T>, update: DataUpdate<T>): Promise<void>;
22
- deleteDocument<T extends Data>(ref: DocumentReference<T>): Promise<void>;
23
- getQuery<T extends Data>(ref: QueryReference<T>): Promise<Entities<T>>;
24
- subscribeQuery<T extends Data>(ref: QueryReference<T>, observer: Observer<Entities<T>>): Unsubscribe;
25
- setQuery<T extends Data>(ref: QueryReference<T>, data: T): Promise<number>;
26
- updateQuery<T extends Data>(ref: QueryReference<T>, update: DataUpdate<T>): Promise<number>;
27
- deleteQuery<T extends Data>(ref: QueryReference<T>): Promise<number>;
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 DocumentReference for a given document. */
32
- function getDocument(firestore, { collection, id }) {
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 getCollection(firestore, { collection }) {
34
+ function _getCollection(firestore, { collection }) {
37
35
  return firestoreCollection(firestore, collection);
38
36
  }
39
- /** Create a corresponding `QueryReference` from a Query. */
40
- function getQuery(firestore, ref) {
41
- return firestoreQuery(getCollection(firestore, ref), ...yieldQueryConstraints(ref));
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* yieldQueryConstraints({ sorts, filters, limit }) {
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 getEntities(snapshot) {
52
- return snapshot.docs.map(getEntity);
49
+ function _getEntities(snapshot) {
50
+ return snapshot.docs.map(_getEntity);
53
51
  }
54
- function getEntity(snapshot) {
52
+ function _getEntity(snapshot) {
55
53
  const data = snapshot.data();
56
54
  return { ...data, id: snapshot.id };
57
55
  }
58
- function getOptionalEntity(snapshot) {
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* yieldFieldValues(updates, prefix = "") {
61
+ function* _getFieldValues(updates, prefix = "") {
64
62
  for (const [key, update] of updates) {
65
- if (!(update instanceof Update))
66
- yield [`${prefix}${key}`, update];
67
- else if (update instanceof Delete)
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 && update.deletes.length)
75
- throw new UnsupportedError("Cannot add/delete array items in one update");
76
- if (update.adds.length)
77
- yield [`${prefix}${key}`, firestoreArrayUnion(...update.adds)];
78
- else if (update.deletes.length)
79
- yield [`${prefix}${key}`, firestoreArrayRemove(...update.deletes)];
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 extends Provider {
95
+ export class FirestoreClientProvider {
92
96
  constructor(firestore) {
93
- super();
94
97
  this.firestore = firestore;
95
98
  }
96
99
  async getDocument(ref) {
97
- return getOptionalEntity(await getDoc(getDocument(this.firestore, ref)));
100
+ return _getOptionalEntity(await getDoc(_getDocument(this.firestore, ref)));
98
101
  }
99
102
  subscribeDocument(ref, observer) {
100
- return onSnapshot(getDocument(this.firestore, ref), snapshot => dispatchNext(observer, getOptionalEntity(snapshot)), thrown => dispatchError(observer, thrown));
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(getCollection(this.firestore, ref), data);
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(getDocument(this.firestore, ref), data);
110
+ await setDoc(_getDocument(this.firestore, ref), data);
108
111
  }
109
112
  async updateDocument(ref, update) {
110
- const fieldValues = Object.fromEntries(yieldFieldValues(update));
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(getDocument(this.firestore, ref));
116
+ await deleteDoc(_getDocument(this.firestore, ref));
115
117
  }
116
118
  async getQuery(ref) {
117
- return getEntities(await getDocs(getQuery(this.firestore, ref)));
119
+ return _getEntities(await getDocs(_getQuery(this.firestore, ref)));
118
120
  }
119
121
  subscribeQuery(ref, observer) {
120
- return onSnapshot(getQuery(this.firestore, ref), snapshot => dispatchNext(observer, getEntities(snapshot)), thrown => dispatchError(observer, thrown));
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(getQuery(this.firestore, ref));
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(getQuery(this.firestore, ref));
129
- const fieldValues = Object.fromEntries(yieldFieldValues(update));
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(getQuery(this.firestore, ref));
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 { DocumentReference, QueryReference } from "../../db/Reference.js";
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 { AsynchronousProvider, Provider } from "../../provider/Provider.js";
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 FirestoreClientProvider extends Provider implements AsynchronousProvider {
12
+ export declare class FirestoreLiteProvider<T extends Datas> implements AsyncProvider<T> {
14
13
  readonly firestore: Firestore;
15
14
  constructor(firestore: Firestore);
16
- getDocument<T extends Data>(ref: DocumentReference<T>): Promise<OptionalEntity<T>>;
15
+ getDocument<K extends Key<T>>(ref: ProviderDocument<T, K>): Promise<OptionalEntity<T[K]>>;
17
16
  subscribeDocument(): Unsubscribe;
18
- addDocument<T extends Data>(ref: QueryReference<T>, data: T): Promise<string>;
19
- setDocument<T extends Data>(ref: DocumentReference<T>, data: T): Promise<void>;
20
- updateDocument<T extends Data>(ref: DocumentReference<T>, update: DataUpdate<T>): Promise<void>;
21
- deleteDocument<T extends Data>(ref: DocumentReference<T>): Promise<void>;
22
- getQuery<T extends Data>(ref: QueryReference<T>): Promise<Entities<T>>;
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<T extends Data>(ref: QueryReference<T>, data: T): Promise<number>;
25
- updateQuery<T extends Data>(ref: QueryReference<T>, update: DataUpdate<T>): Promise<number>;
26
- deleteQuery<T extends Data>(ref: QueryReference<T>): Promise<number>;
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 getDocument(firestore, { collection, id }) {
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 getCollection(firestore, { collection }) {
34
+ function _getCollection(firestore, { collection }) {
36
35
  return firestoreCollection(firestore, collection);
37
36
  }
38
37
  /** Create a corresponding `QueryReference` from a Query. */
39
- function getQuery(firestore, ref) {
40
- return firestoreQuery(getCollection(firestore, ref), ...yieldQueryConstraints(ref));
38
+ function _getQuery(firestore, ref) {
39
+ return firestoreQuery(_getCollection(firestore, ref), ..._yieldQueryConstraints(ref));
41
40
  }
42
- function* yieldQueryConstraints({ sorts, filters, limit }) {
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 getEntities(snapshot) {
51
- return snapshot.docs.map(getEntity);
49
+ function _getEntities(snapshot) {
50
+ return snapshot.docs.map(_getEntity);
52
51
  }
53
- function getEntity(snapshot) {
52
+ function _getEntity(snapshot) {
54
53
  const data = snapshot.data();
55
54
  return { ...data, id: snapshot.id };
56
55
  }
57
- function getOptionalData(snapshot) {
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* yieldFieldValues(updates, prefix = "") {
61
+ function* _getFieldValues(updates, prefix = "") {
63
62
  for (const [key, update] of updates) {
64
- if (!(update instanceof Update))
65
- yield [`${prefix}${key}`, update];
66
- else if (update instanceof Delete)
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 && update.deletes.length)
74
- throw new UnsupportedError("Cannot add/delete array items in one update");
75
- if (update.adds.length)
76
- yield [`${prefix}${key}`, firestoreArrayUnion(...update.adds)];
77
- else if (update.deletes.length)
78
- yield [`${prefix}${key}`, firestoreArrayRemove(...update.deletes)];
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 FirestoreClientProvider extends Provider {
95
+ export class FirestoreLiteProvider {
91
96
  constructor(firestore) {
92
- super();
93
97
  this.firestore = firestore;
94
98
  }
95
99
  async getDocument(ref) {
96
- return getOptionalData(await getDoc(getDocument(this.firestore, ref)));
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(getCollection(this.firestore, ref), data);
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(getDocument(this.firestore, ref), data);
110
+ await setDoc(_getDocument(this.firestore, ref), data);
107
111
  }
108
112
  async updateDocument(ref, update) {
109
- const fieldValues = Object.fromEntries(yieldFieldValues(update));
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(getDocument(this.firestore, ref));
116
+ await deleteDoc(_getDocument(this.firestore, ref));
114
117
  }
115
118
  async getQuery(ref) {
116
- return getEntities(await getDocs(getQuery(this.firestore, ref)));
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(getQuery(this.firestore, ref));
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(getQuery(this.firestore, ref));
128
- const fieldValues = Object.fromEntries(yieldFieldValues(update));
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(getQuery(this.firestore, ref));
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 { DocumentReference, QueryReference } from "../../db/Reference.js";
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 Provider implements AsynchronousProvider {
11
+ export declare class FirestoreServerProvider<T extends Datas> implements AsyncProvider<T> {
13
12
  readonly firestore: Firestore;
14
13
  constructor(firestore?: Firestore);
15
- getDocument<T extends Data>(ref: DocumentReference<T>): Promise<OptionalEntity<T>>;
16
- subscribeDocument<T extends Data>(ref: DocumentReference<T>, observer: Observer<OptionalEntity<T>>): Unsubscribe;
17
- addDocument<T extends Data>(ref: QueryReference<T>, data: T): Promise<string>;
18
- setDocument<T extends Data>(ref: DocumentReference<T>, data: T): Promise<void>;
19
- updateDocument<T extends Data>(ref: DocumentReference<T>, update: DataUpdate<T>): Promise<void>;
20
- deleteDocument<T extends Data>(ref: DocumentReference<T>): Promise<void>;
21
- getQuery<T extends Data>(ref: QueryReference<T>): Promise<Entities<T>>;
22
- subscribeQuery<T extends Data>(ref: QueryReference<T>, observer: Observer<Entities<T>>): Unsubscribe;
23
- setQuery<T extends Data>(ref: QueryReference<T>, data: T): Promise<number>;
24
- updateQuery<T extends Data>(ref: QueryReference<T>, update: DataUpdate<T>): Promise<number>;
25
- deleteQuery<T extends Data>(ref: QueryReference<T>): Promise<number>;
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
  }