shelving 1.7.1 → 1.10.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 (61) hide show
  1. package/db/Document.d.ts +2 -5
  2. package/db/Document.js +6 -11
  3. package/db/DocumentState.d.ts +2 -2
  4. package/db/DocumentState.js +2 -2
  5. package/db/Documents.d.ts +2 -4
  6. package/db/Documents.js +5 -6
  7. package/db/MemoryProvider.d.ts +3 -3
  8. package/db/MemoryProvider.js +7 -7
  9. package/db/Provider.d.ts +5 -5
  10. package/db/Reference.d.ts +17 -0
  11. package/db/Reference.js +35 -0
  12. package/db/StateProvider.d.ts +2 -2
  13. package/db/StateProvider.js +3 -3
  14. package/db/ValidationProvider.d.ts +3 -3
  15. package/db/ValidationProvider.js +66 -25
  16. package/db/errors.d.ts +12 -5
  17. package/db/errors.js +15 -6
  18. package/db/index.d.ts +1 -0
  19. package/db/index.js +1 -0
  20. package/firestore-client/FirestoreClientProvider.d.ts +3 -4
  21. package/firestore-client/FirestoreClientProvider.js +39 -13
  22. package/firestore-server/FirestoreServerProvider.d.ts +3 -4
  23. package/firestore-server/FirestoreServerProvider.js +38 -13
  24. package/package.json +10 -10
  25. package/react/usePureMemo.d.ts +11 -6
  26. package/react/usePureMemo.js +3 -3
  27. package/schema/ObjectSchema.d.ts +1 -2
  28. package/schema/ObjectSchema.js +3 -5
  29. package/schema/ObjectSchema.test.js +0 -6
  30. package/stream/ArrayState.d.ts +20 -0
  31. package/stream/ArrayState.js +37 -0
  32. package/stream/ArrayState.test.d.ts +1 -0
  33. package/stream/ArrayState.test.js +30 -0
  34. package/stream/MapState.d.ts +16 -0
  35. package/stream/MapState.js +29 -0
  36. package/stream/State.d.ts +2 -23
  37. package/stream/State.js +3 -33
  38. package/stream/State.test.js +0 -28
  39. package/stream/index.d.ts +2 -0
  40. package/stream/index.js +2 -0
  41. package/tsconfig.build.tsbuildinfo +1 -1
  42. package/util/array.d.ts +125 -39
  43. package/util/array.js +191 -34
  44. package/util/array.test.js +42 -1
  45. package/util/class.d.ts +2 -0
  46. package/util/class.js +3 -0
  47. package/util/function.d.ts +8 -1
  48. package/util/function.js +2 -1
  49. package/util/index.d.ts +2 -1
  50. package/util/index.js +2 -1
  51. package/util/number.d.ts +8 -0
  52. package/util/number.js +8 -0
  53. package/util/object.d.ts +122 -39
  54. package/util/object.js +143 -72
  55. package/util/object.test.js +102 -73
  56. package/util/string.d.ts +4 -0
  57. package/util/string.js +5 -1
  58. package/util/template.d.ts +1 -1
  59. package/util/template.js +2 -1
  60. package/util/transform.d.ts +85 -0
  61. package/util/transform.js +117 -0
package/db/Document.d.ts CHANGED
@@ -1,13 +1,11 @@
1
1
  import { Data, Observable, Result, Observer, Unsubscriber, AsyncDispatcher, AsyncCatcher, AsyncEmptyDispatcher } from "../util";
2
2
  import type { Database } from "./Database";
3
3
  import { DocumentState } from "./DocumentState";
4
+ import { Reference } from "./Reference";
4
5
  /**
5
6
  * Document reference: allows reading from / writing to a specific document in a database.
6
7
  */
7
- export declare class Document<T extends Data = Data> implements Observable<Result<T>> {
8
- readonly db: Database;
9
- readonly path: string;
10
- readonly collection: string;
8
+ export declare class Document<T extends Data = Data> extends Reference<T> implements Observable<Result<T>> {
11
9
  readonly id: string;
12
10
  constructor(db: Database, collection: string, id: string);
13
11
  /**
@@ -108,5 +106,4 @@ export declare class Document<T extends Data = Data> implements Observable<Resul
108
106
  * @throws Error If the document does not exist (ideally a `RequiredError` but may be provider-specific).
109
107
  */
110
108
  delete(): void | Promise<void>;
111
- toString(): string;
112
109
  }
package/db/Document.js CHANGED
@@ -1,14 +1,13 @@
1
1
  import { throwAsync, isAsync } from "../util";
2
2
  import { DocumentState } from "./DocumentState";
3
- import { DocumentRequiredError } from "./errors";
3
+ import { ReferenceRequiredError } from "./errors";
4
+ import { Reference } from "./Reference";
4
5
  /**
5
6
  * Document reference: allows reading from / writing to a specific document in a database.
6
7
  */
7
- export class Document {
8
+ export class Document extends Reference {
8
9
  constructor(db, collection, id) {
9
- this.db = db;
10
- this.path = `${collection}/${id}`;
11
- this.collection = collection;
10
+ super(db, collection, `${collection}/${id}`);
12
11
  this.id = id;
13
12
  }
14
13
  /**
@@ -77,11 +76,11 @@ export class Document {
77
76
  if (isAsync(result))
78
77
  return result.then(r => {
79
78
  if (!r)
80
- throw new DocumentRequiredError(this);
79
+ throw new ReferenceRequiredError(this);
81
80
  return r;
82
81
  });
83
82
  if (!result)
84
- throw new DocumentRequiredError(this);
83
+ throw new ReferenceRequiredError(this);
85
84
  return result;
86
85
  }
87
86
  /**
@@ -130,8 +129,4 @@ export class Document {
130
129
  delete() {
131
130
  return this.db.provider.deleteDocument(this);
132
131
  }
133
- // Implement toString()
134
- toString() {
135
- return this.path;
136
- }
137
132
  }
@@ -1,5 +1,5 @@
1
1
  import { State } from "../stream";
2
- import { Data, LOADING, Observer, Result, Unsubscriber } from "../util";
2
+ import { Data, LOADING, Observer, Result, Transforms, Unsubscriber } from "../util";
3
3
  import type { Document } from "./Document";
4
4
  /**
5
5
  * Document state: stores the global state of a specific document.
@@ -10,7 +10,7 @@ export declare class DocumentState<T extends Data = Data> extends State<Result<T
10
10
  #private;
11
11
  static get<X extends Data>(ref: Document<X>): DocumentState<X>;
12
12
  static set<X extends Data>(ref: Document<X>, result: Result<X> | Promise<Result<X>>): void;
13
- static update<X extends Data>(ref: Document<X>, data: Partial<X>): void;
13
+ static update<X extends Data>(ref: Document<X>, transforms: Transforms<X>): void;
14
14
  static start<X extends Data>(ref: Document<X>, observer?: Observer<Result<X>>): Unsubscriber;
15
15
  /** Whether we currently have an active realtime subscription, or not. */
16
16
  get started(): boolean;
@@ -45,11 +45,11 @@ export class DocumentState extends State {
45
45
  else
46
46
  __classPrivateFieldGet(this, _a, "f", _DocumentState_states)[key] = new DocumentState(ref, result);
47
47
  }
48
- static update(ref, data) {
48
+ static update(ref, transforms) {
49
49
  const key = ref.toString();
50
50
  const state = __classPrivateFieldGet(this, _a, "f", _DocumentState_states)[key];
51
51
  if (state && !state.loading && !state.closed)
52
- state.update(data);
52
+ state.update(transforms);
53
53
  }
54
54
  static start(ref, observer) {
55
55
  const key = ref.toString();
package/db/Documents.d.ts CHANGED
@@ -3,13 +3,11 @@ import { Query, Queryable } from "../query";
3
3
  import type { Database } from "./Database";
4
4
  import { Document } from "./Document";
5
5
  import { DocumentsState } from "./DocumentsState";
6
+ import { Reference } from "./Reference";
6
7
  /**
7
8
  * Documents reference: allows reading from / writing to a list of documents in a database, optionally with query filtering and sorting.
8
9
  */
9
- export declare class Documents<T extends Data = Data> implements Queryable<T>, Observable<Results<T>> {
10
- readonly db: Database;
11
- readonly path: string;
12
- readonly collection: string;
10
+ export declare class Documents<T extends Data = Data> extends Reference<T> implements Queryable<T>, Observable<Results<T>> {
13
11
  readonly query: Query<T>;
14
12
  constructor(db: Database, collection: string, query?: Query<T>);
15
13
  /**
package/db/Documents.js CHANGED
@@ -1,17 +1,16 @@
1
- import { throwAsync, isAsync, countProps, getFirstProp, getLastProp, } from "../util";
1
+ import { throwAsync, isAsync, countEntries, getFirstProp, getLastProp, } from "../util";
2
2
  import { Query } from "../query";
3
3
  import { Document } from "./Document";
4
4
  import { DocumentsState } from "./DocumentsState";
5
+ import { Reference } from "./Reference";
5
6
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
7
  const EMPTY_QUERY = new Query();
7
8
  /**
8
9
  * Documents reference: allows reading from / writing to a list of documents in a database, optionally with query filtering and sorting.
9
10
  */
10
- export class Documents {
11
+ export class Documents extends Reference {
11
12
  constructor(db, collection, query = EMPTY_QUERY) {
12
- this.db = db;
13
- this.path = collection;
14
- this.collection = collection;
13
+ super(db, collection, collection);
15
14
  this.query = query;
16
15
  }
17
16
  /**
@@ -74,7 +73,7 @@ export class Documents {
74
73
  */
75
74
  get asyncCount() {
76
75
  const results = this.db.provider.getDocuments(this);
77
- return isAsync(results) ? results.then(countProps) : countProps(results);
76
+ return isAsync(results) ? results.then(countEntries) : countEntries(results);
78
77
  }
79
78
  /**
80
79
  * Get an array of string IDs for this set of documents (asynchronously).
@@ -1,4 +1,4 @@
1
- import { Data, Result, Results, Unsubscriber, Observer } from "../util";
1
+ import { Data, Result, Results, Unsubscriber, Observer, Transforms } from "../util";
2
2
  import type { Provider } from "./Provider";
3
3
  import type { Documents } from "./Documents";
4
4
  import type { Document } from "./Document";
@@ -16,12 +16,12 @@ export declare class MemoryProvider implements Provider {
16
16
  onDocument<X extends Data>(ref: Document<X>, observer: Observer<Result<X>>): Unsubscriber;
17
17
  addDocument<X extends Data>(ref: Documents<X>, data: X): string;
18
18
  setDocument<X extends Data>(ref: Document<X>, data: X): void;
19
- updateDocument<X extends Data>(ref: Document<X>, data: Partial<X>): void;
19
+ updateDocument<X extends Data>(ref: Document<X>, transforms: Transforms<X>): void;
20
20
  deleteDocument<X extends Data>(ref: Document<X>): void;
21
21
  getDocuments<X extends Data>(ref: Documents<X>): Results<X>;
22
22
  onDocuments<X extends Data>(ref: Documents<X>, observer: Observer<Results<X>>): Unsubscriber;
23
23
  setDocuments<X extends Data>(ref: Documents<X>, data: X): void;
24
- updateDocuments<X extends Data>(ref: Documents<X>, data: Partial<X>): void;
24
+ updateDocuments<X extends Data>(ref: Documents<X>, transforms: Transforms<X>): void;
25
25
  deleteDocuments<X extends Data>(ref: Documents<X>): void;
26
26
  reset(): void;
27
27
  }
@@ -10,8 +10,8 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
12
  var _MemoryProvider_instances, _MemoryProvider_tables, _MemoryProvider_table, _Table_dispatchers, _Table_changes, _Table_results;
13
- import { randomId, objectFromEntries, updateProps, addItem, removeItem, dispatch, dispatchNext, thispatch, } from "../util";
14
- import { DocumentRequiredError } from "./errors";
13
+ import { randomId, objectFromEntries, addItem, removeItem, dispatch, dispatchNext, thispatch, transformProps, } from "../util";
14
+ import { ReferenceRequiredError } from "./errors";
15
15
  /**
16
16
  * Memory provider: fast in-memory store for data.
17
17
  *
@@ -52,13 +52,13 @@ export class MemoryProvider {
52
52
  setDocument(ref, data) {
53
53
  __classPrivateFieldGet(this, _MemoryProvider_instances, "m", _MemoryProvider_table).call(this, ref).set(ref.id, data);
54
54
  }
55
- updateDocument(ref, data) {
55
+ updateDocument(ref, transforms) {
56
56
  const table = __classPrivateFieldGet(this, _MemoryProvider_instances, "m", _MemoryProvider_table).call(this, ref);
57
57
  const id = ref.id;
58
58
  const existing = table.result(id);
59
59
  if (!existing)
60
- throw new DocumentRequiredError(ref);
61
- table.set(id, updateProps(existing, data));
60
+ throw new ReferenceRequiredError(ref);
61
+ table.set(id, transformProps(existing, transforms));
62
62
  }
63
63
  deleteDocument(ref) {
64
64
  __classPrivateFieldGet(this, _MemoryProvider_instances, "m", _MemoryProvider_table).call(this, ref).set(ref.id, undefined);
@@ -113,11 +113,11 @@ export class MemoryProvider {
113
113
  for (const [id] of entries)
114
114
  table.set(id, data);
115
115
  }
116
- updateDocuments(ref, data) {
116
+ updateDocuments(ref, transforms) {
117
117
  const table = __classPrivateFieldGet(this, _MemoryProvider_instances, "m", _MemoryProvider_table).call(this, ref);
118
118
  const entries = ref.query.apply(Object.entries(table.results()));
119
119
  for (const [id, existing] of entries)
120
- table.set(id, updateProps(existing, data));
120
+ table.set(id, transformProps(existing, transforms));
121
121
  }
122
122
  deleteDocuments(ref) {
123
123
  const table = __classPrivateFieldGet(this, _MemoryProvider_instances, "m", _MemoryProvider_table).call(this, ref);
package/db/Provider.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Observer, Unsubscriber, Data, Result, Results } from "../util";
1
+ import type { Observer, Unsubscriber, Data, Result, Results, Transforms } from "../util";
2
2
  import type { Document } from "./Document";
3
3
  import type { Documents } from "./Documents";
4
4
  /**
@@ -49,12 +49,12 @@ export interface Provider {
49
49
  * - If the document doesn't exist, throw an error.
50
50
  *
51
51
  * @param ref Document reference specifying which document to merge into.
52
- * @param data Partial data to merge into the existing document.
52
+ * @param transforms Set of transforms to apply to the existing document.
53
53
  *
54
54
  * @return Nothing (possibly promised).
55
55
  * @throws Error If the document does not exist (ideally a `RequiredError` but may be provider-specific).
56
56
  */
57
- updateDocument<X extends Data>(ref: Document<X>, data: Partial<X>): void | Promise<void>;
57
+ updateDocument<X extends Data>(ref: Document<X>, transforms: Transforms<X>): void | Promise<void>;
58
58
  /**
59
59
  * Delete an existing document.
60
60
  * - If the document doesn't exist, throw an error.
@@ -95,11 +95,11 @@ export interface Provider {
95
95
  * Update all matching documents with the same partial value.
96
96
  *
97
97
  * @param ref Documents reference specifying which collection to update.
98
- * @param data Partial data to merge into every matching document.
98
+ * @param transforms Set of transforms to apply to every matching document.
99
99
  *
100
100
  * @return Nothing (possibly promised).
101
101
  */
102
- updateDocuments<X extends Data>(ref: Documents<X>, data: Partial<X>): void | Promise<void>;
102
+ updateDocuments<X extends Data>(ref: Documents<X>, transforms: Transforms<X>): void | Promise<void>;
103
103
  /**
104
104
  * Delete all matching documents.
105
105
  *
@@ -0,0 +1,17 @@
1
+ import { ObjectSchema, Validator } from "../schema";
2
+ import { Data } from "../util";
3
+ import type { Database } from "./Database";
4
+ /**
5
+ * Reference: a location in a database
6
+ * - This class is a shared base for both `Document` and `Documents`
7
+ */
8
+ export declare class Reference<T extends Data = Data> implements Validator<T> {
9
+ readonly db: Database;
10
+ readonly collection: string;
11
+ readonly path: string;
12
+ constructor(db: Database, collection: string, path: string);
13
+ /** Get the corresponding `ObjectSchema` for this reference. */
14
+ get schema(): ObjectSchema<T>;
15
+ validate(data: unknown): T;
16
+ toString(): string;
17
+ }
@@ -0,0 +1,35 @@
1
+ import { isFeedback } from "../feedback";
2
+ import { ObjectSchema } from "../schema";
3
+ import { assertInstance } from "../util";
4
+ import { ReferenceValidationError } from "./errors";
5
+ /**
6
+ * Reference: a location in a database
7
+ * - This class is a shared base for both `Document` and `Documents`
8
+ */
9
+ export class Reference {
10
+ constructor(db, collection, path) {
11
+ this.db = db;
12
+ this.collection = collection;
13
+ this.path = path;
14
+ }
15
+ /** Get the corresponding `ObjectSchema` for this reference. */
16
+ get schema() {
17
+ const schema = this.db.schemas[this.collection];
18
+ assertInstance(schema, ObjectSchema);
19
+ return schema;
20
+ }
21
+ // Implement `Validator`
22
+ validate(data) {
23
+ const schema = this.schema;
24
+ try {
25
+ return schema.validate(data);
26
+ }
27
+ catch (thrown) {
28
+ throw isFeedback(thrown) ? new ReferenceValidationError(this, thrown) : thrown;
29
+ }
30
+ }
31
+ // Implement `toString()`
32
+ toString() {
33
+ return this.path;
34
+ }
35
+ }
@@ -1,4 +1,4 @@
1
- import { Data, Result, Results, Unsubscriber, Observer } from "../util";
1
+ import { Data, Result, Results, Unsubscriber, Observer, Transforms } from "../util";
2
2
  import type { Document } from "./Document";
3
3
  import type { Documents } from "./Documents";
4
4
  import type { Provider } from "./Provider";
@@ -12,7 +12,7 @@ export declare class StateProvider implements Provider {
12
12
  onDocument<X extends Data>(ref: Document<X>, observer: Observer<Result<X>>): Unsubscriber;
13
13
  addDocument<X extends Data>(ref: Documents<X>, data: X): Promise<string>;
14
14
  setDocument<X extends Data>(ref: Document<X>, data: X): Promise<void>;
15
- updateDocument<X extends Data>(ref: Document<X>, data: Partial<X>): Promise<void>;
15
+ updateDocument<X extends Data>(ref: Document<X>, transforms: Transforms<X>): Promise<void>;
16
16
  deleteDocument<X extends Data>(ref: Document<X>): Promise<void>;
17
17
  getDocuments<X extends Data>(ref: Documents<X>): Results<X> | Promise<Results<X>>;
18
18
  onDocuments<X extends Data>(ref: Documents<X>, observer: Observer<Results<X>>): Unsubscriber;
@@ -37,9 +37,9 @@ export class StateProvider {
37
37
  await __classPrivateFieldGet(this, _StateProvider_source, "f").setDocument(ref, data);
38
38
  DocumentState.set(ref, data);
39
39
  }
40
- async updateDocument(ref, data) {
41
- await __classPrivateFieldGet(this, _StateProvider_source, "f").updateDocument(ref, data);
42
- DocumentState.update(ref, data);
40
+ async updateDocument(ref, transforms) {
41
+ await __classPrivateFieldGet(this, _StateProvider_source, "f").updateDocument(ref, transforms);
42
+ DocumentState.update(ref, transforms);
43
43
  }
44
44
  async deleteDocument(ref) {
45
45
  await __classPrivateFieldGet(this, _StateProvider_source, "f").deleteDocument(ref);
@@ -1,4 +1,4 @@
1
- import { Data, Result, Results, Unsubscriber, Observer } from "../util";
1
+ import { Data, Result, Results, Unsubscriber, Observer, Transforms } from "../util";
2
2
  import type { Provider } from "./Provider";
3
3
  import type { Document } from "./Document";
4
4
  import type { Documents } from "./Documents";
@@ -12,11 +12,11 @@ export declare class ValidationProvider implements Provider {
12
12
  onDocument<X extends Data>(ref: Document<X>, observer: Observer<Result>): Unsubscriber;
13
13
  addDocument<X extends Data>(ref: Documents<X>, data: X): string | Promise<string>;
14
14
  setDocument<X extends Data>(ref: Document<X>, data: X): void | Promise<void>;
15
- updateDocument<X extends Data>(ref: Document<X>, data: Partial<X>): void | Promise<void>;
15
+ updateDocument<X extends Data>(ref: Document<X>, transforms: Transforms<X>): void | Promise<void>;
16
16
  deleteDocument<X extends Data>(ref: Document<X>): void | Promise<void>;
17
17
  getDocuments<X extends Data>(ref: Documents<X>): Results<X> | Promise<Results<X>>;
18
18
  onDocuments<X extends Data>(ref: Documents<X>, observer: Observer<Results<X>>): Unsubscriber;
19
19
  setDocuments<X extends Data>(ref: Documents<X>, data: X): void | Promise<void>;
20
- updateDocuments<X extends Data>(ref: Documents<X>, data: Partial<X>): void | Promise<void>;
20
+ updateDocuments<X extends Data>(ref: Documents<X>, transforms: Transforms<X>): void | Promise<void>;
21
21
  deleteDocuments<X extends Data>(ref: Documents<X>): void | Promise<void>;
22
22
  }
@@ -10,11 +10,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
12
  var _ValidationProvider_instances, _ValidationProvider_source, _ValidationProvider_awaitGetDocument, _ValidationProvider_awaitGetDocuments;
13
- import { isAsync } from "../util";
14
- import { ValidationError } from "../errors";
13
+ import { isAsync, isObject, isTransform } from "../util";
15
14
  import { InvalidFeedback, isFeedback } from "../feedback";
16
- import { ObjectSchema, Schema } from "../schema";
17
15
  import { Stream } from "../stream";
16
+ import { ReferenceValidationError } from "./errors";
18
17
  /**
19
18
  * Validation provider: validates any values that are read from or written a the source provider.
20
19
  */
@@ -28,10 +27,10 @@ export class ValidationProvider {
28
27
  const result = __classPrivateFieldGet(this, _ValidationProvider_source, "f").getDocument(ref);
29
28
  if (isAsync(result))
30
29
  return __classPrivateFieldGet(this, _ValidationProvider_instances, "m", _ValidationProvider_awaitGetDocument).call(this, ref, result);
31
- return result ? validateData(ref, result) : undefined;
30
+ return validateResult(ref, result);
32
31
  }
33
32
  onDocument(ref, observer) {
34
- const stream = Stream.derive(v => (v ? validateData(ref, v) : undefined));
33
+ const stream = Stream.derive(v => validateResult(ref, v));
35
34
  stream.subscribe(observer);
36
35
  return __classPrivateFieldGet(this, _ValidationProvider_source, "f").onDocument(ref, stream);
37
36
  }
@@ -41,8 +40,8 @@ export class ValidationProvider {
41
40
  setDocument(ref, data) {
42
41
  return __classPrivateFieldGet(this, _ValidationProvider_source, "f").setDocument(ref, validateData(ref, data));
43
42
  }
44
- updateDocument(ref, data) {
45
- return __classPrivateFieldGet(this, _ValidationProvider_source, "f").updateDocument(ref, validateData(ref, data, true));
43
+ updateDocument(ref, transforms) {
44
+ return __classPrivateFieldGet(this, _ValidationProvider_source, "f").updateDocument(ref, validateTransforms(ref, transforms));
46
45
  }
47
46
  deleteDocument(ref) {
48
47
  return __classPrivateFieldGet(this, _ValidationProvider_source, "f").deleteDocument(ref);
@@ -59,10 +58,10 @@ export class ValidationProvider {
59
58
  return __classPrivateFieldGet(this, _ValidationProvider_source, "f").onDocuments(ref, stream);
60
59
  }
61
60
  setDocuments(ref, data) {
62
- return __classPrivateFieldGet(this, _ValidationProvider_source, "f").setDocuments(ref, validateData(ref, data));
61
+ return __classPrivateFieldGet(this, _ValidationProvider_source, "f").setDocuments(ref, ref.validate(data));
63
62
  }
64
- updateDocuments(ref, data) {
65
- return __classPrivateFieldGet(this, _ValidationProvider_source, "f").updateDocuments(ref, validateData(ref, data, true));
63
+ updateDocuments(ref, transforms) {
64
+ return __classPrivateFieldGet(this, _ValidationProvider_source, "f").updateDocuments(ref, validateTransforms(ref, transforms));
66
65
  }
67
66
  deleteDocuments(ref) {
68
67
  return __classPrivateFieldGet(this, _ValidationProvider_source, "f").deleteDocuments(ref);
@@ -70,41 +69,83 @@ export class ValidationProvider {
70
69
  }
71
70
  _ValidationProvider_source = new WeakMap(), _ValidationProvider_instances = new WeakSet(), _ValidationProvider_awaitGetDocument = async function _ValidationProvider_awaitGetDocument(ref, asyncResult) {
72
71
  const result = await asyncResult;
73
- return result ? validateData(ref, result) : undefined;
72
+ return validateResult(ref, result);
74
73
  }, _ValidationProvider_awaitGetDocuments = async function _ValidationProvider_awaitGetDocuments(ref, asyncResult) {
75
74
  return validateResults(ref, await asyncResult);
76
75
  };
77
- function validateData(ref, data, partial) {
76
+ /** Validate a set of data for a path. */
77
+ function validateData(ref, data) {
78
+ return ref.schema.validate(data);
79
+ }
80
+ /** Validate a set of transforms for a path. */
81
+ function validateTransforms(ref, unsafeTransforms) {
82
+ if (!isObject(unsafeTransforms))
83
+ throw new InvalidFeedback("Must be object", { value: unsafeTransforms });
84
+ const schema = ref.schema;
85
+ let changed = false;
86
+ let invalid = false;
87
+ const safeTransforms = {};
88
+ const details = {};
89
+ const validators = Object.entries(schema.props);
90
+ for (const [key, validator] of validators) {
91
+ const unsafeTransform = unsafeTransforms[key];
92
+ if (unsafeTransform === undefined) {
93
+ continue; // Skip undefined.
94
+ }
95
+ else if (isTransform(unsafeTransform)) {
96
+ safeTransforms[key] = unsafeTransform;
97
+ }
98
+ else {
99
+ try {
100
+ const safeTransform = validator.validate(unsafeTransform);
101
+ if (safeTransform !== unsafeTransform)
102
+ changed = true;
103
+ safeTransforms[key] = safeTransform;
104
+ }
105
+ catch (feedback) {
106
+ invalid = true;
107
+ details[key] = feedback;
108
+ }
109
+ }
110
+ }
111
+ if (Object.keys(unsafeTransforms).length > validators.length)
112
+ changed = true;
113
+ if (invalid)
114
+ throw new InvalidFeedback("Invalid transforms", details);
115
+ return changed ? safeTransforms : unsafeTransforms;
116
+ }
117
+ /** Validate a result for a path. */
118
+ function validateResult(ref, result) {
119
+ if (!result)
120
+ return undefined;
121
+ const schema = ref.schema;
78
122
  try {
79
- const schema = ref.db.schemas[ref.collection];
80
- return schema && schema instanceof ObjectSchema ? schema.validate(data, partial) : data;
123
+ schema.validate(result);
81
124
  }
82
- catch (thrown) {
83
- if (isFeedback(thrown))
84
- throw new ValidationError(`Invalid ${partial ? "partial data" : "data"} for: "${ref.path}"`, thrown);
85
- else
86
- throw thrown;
125
+ catch (err) {
126
+ throw isFeedback(err) ? new ReferenceValidationError(ref, err) : err;
87
127
  }
88
128
  }
89
- /** Validate a set of documents at this path. */
129
+ /** Validate a set of results for a path. */
90
130
  function validateResults(ref, results) {
131
+ const schema = ref.schema;
91
132
  const validated = {};
92
133
  const invalids = {};
93
134
  let invalid = false;
94
135
  for (const [id, data] of Object.entries(results)) {
95
136
  try {
96
- const schema = ref.db.schemas[ref.collection];
97
- validated[id] = schema && schema instanceof Schema ? schema.validate(data) : data;
137
+ validated[id] = schema.validate(data);
98
138
  }
99
139
  catch (thrown) {
100
- if (isFeedback(thrown))
140
+ if (isFeedback(thrown)) {
101
141
  invalids[id] = thrown;
142
+ invalid = true;
143
+ }
102
144
  else
103
145
  throw thrown;
104
- invalid = true;
105
146
  }
106
147
  }
107
148
  if (invalid)
108
- throw new ValidationError(`Invalid documents for "${ref.path}"`, new InvalidFeedback("Invalid documents", invalids));
149
+ throw new ReferenceValidationError(ref, new InvalidFeedback("Invalid documents", invalids));
109
150
  return validated;
110
151
  }