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.
- package/db/Document.d.ts +2 -5
- package/db/Document.js +6 -11
- package/db/DocumentState.d.ts +2 -2
- package/db/DocumentState.js +2 -2
- package/db/Documents.d.ts +2 -4
- package/db/Documents.js +5 -6
- package/db/MemoryProvider.d.ts +3 -3
- package/db/MemoryProvider.js +7 -7
- package/db/Provider.d.ts +5 -5
- package/db/Reference.d.ts +17 -0
- package/db/Reference.js +35 -0
- package/db/StateProvider.d.ts +2 -2
- package/db/StateProvider.js +3 -3
- package/db/ValidationProvider.d.ts +3 -3
- package/db/ValidationProvider.js +66 -25
- package/db/errors.d.ts +12 -5
- package/db/errors.js +15 -6
- package/db/index.d.ts +1 -0
- package/db/index.js +1 -0
- package/firestore-client/FirestoreClientProvider.d.ts +3 -4
- package/firestore-client/FirestoreClientProvider.js +39 -13
- package/firestore-server/FirestoreServerProvider.d.ts +3 -4
- package/firestore-server/FirestoreServerProvider.js +38 -13
- package/package.json +10 -10
- package/react/usePureMemo.d.ts +11 -6
- package/react/usePureMemo.js +3 -3
- package/schema/ObjectSchema.d.ts +1 -2
- package/schema/ObjectSchema.js +3 -5
- package/schema/ObjectSchema.test.js +0 -6
- package/stream/ArrayState.d.ts +20 -0
- package/stream/ArrayState.js +37 -0
- package/stream/ArrayState.test.d.ts +1 -0
- package/stream/ArrayState.test.js +30 -0
- package/stream/MapState.d.ts +16 -0
- package/stream/MapState.js +29 -0
- package/stream/State.d.ts +2 -23
- package/stream/State.js +3 -33
- package/stream/State.test.js +0 -28
- package/stream/index.d.ts +2 -0
- package/stream/index.js +2 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/util/array.d.ts +125 -39
- package/util/array.js +191 -34
- package/util/array.test.js +42 -1
- package/util/class.d.ts +2 -0
- package/util/class.js +3 -0
- package/util/function.d.ts +8 -1
- package/util/function.js +2 -1
- package/util/index.d.ts +2 -1
- package/util/index.js +2 -1
- package/util/number.d.ts +8 -0
- package/util/number.js +8 -0
- package/util/object.d.ts +122 -39
- package/util/object.js +143 -72
- package/util/object.test.js +102 -73
- package/util/string.d.ts +4 -0
- package/util/string.js +5 -1
- package/util/template.d.ts +1 -1
- package/util/template.js +2 -1
- package/util/transform.d.ts +85 -0
- 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 {
|
|
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
|
-
|
|
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
|
|
79
|
+
throw new ReferenceRequiredError(this);
|
|
81
80
|
return r;
|
|
82
81
|
});
|
|
83
82
|
if (!result)
|
|
84
|
-
throw new
|
|
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
|
}
|
package/db/DocumentState.d.ts
CHANGED
|
@@ -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>,
|
|
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;
|
package/db/DocumentState.js
CHANGED
|
@@ -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,
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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(
|
|
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).
|
package/db/MemoryProvider.d.ts
CHANGED
|
@@ -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>,
|
|
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>,
|
|
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
|
}
|
package/db/MemoryProvider.js
CHANGED
|
@@ -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,
|
|
14
|
-
import {
|
|
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,
|
|
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
|
|
61
|
-
table.set(id,
|
|
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,
|
|
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,
|
|
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
|
|
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>,
|
|
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
|
|
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>,
|
|
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
|
+
}
|
package/db/Reference.js
ADDED
|
@@ -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
|
+
}
|
package/db/StateProvider.d.ts
CHANGED
|
@@ -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>,
|
|
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;
|
package/db/StateProvider.js
CHANGED
|
@@ -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,
|
|
41
|
-
await __classPrivateFieldGet(this, _StateProvider_source, "f").updateDocument(ref,
|
|
42
|
-
DocumentState.update(ref,
|
|
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>,
|
|
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>,
|
|
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
|
}
|
package/db/ValidationProvider.js
CHANGED
|
@@ -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
|
|
30
|
+
return validateResult(ref, result);
|
|
32
31
|
}
|
|
33
32
|
onDocument(ref, observer) {
|
|
34
|
-
const stream = Stream.derive(v => (
|
|
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,
|
|
45
|
-
return __classPrivateFieldGet(this, _ValidationProvider_source, "f").updateDocument(ref,
|
|
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,
|
|
61
|
+
return __classPrivateFieldGet(this, _ValidationProvider_source, "f").setDocuments(ref, ref.validate(data));
|
|
63
62
|
}
|
|
64
|
-
updateDocuments(ref,
|
|
65
|
-
return __classPrivateFieldGet(this, _ValidationProvider_source, "f").updateDocuments(ref,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
80
|
-
return schema && schema instanceof ObjectSchema ? schema.validate(data, partial) : data;
|
|
123
|
+
schema.validate(result);
|
|
81
124
|
}
|
|
82
|
-
catch (
|
|
83
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
149
|
+
throw new ReferenceValidationError(ref, new InvalidFeedback("Invalid documents", invalids));
|
|
109
150
|
return validated;
|
|
110
151
|
}
|