shelving 1.51.4 → 1.52.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.
- package/db/Database.js +4 -4
- package/db/errors.d.ts +28 -4
- package/db/errors.js +43 -7
- package/package.json +5 -5
- package/query/Query.js +1 -1
- package/query/Rules.js +1 -1
- package/react/useDocument.js +22 -10
- package/react/useQuery.js +19 -7
- package/util/jsx.d.ts +2 -2
package/db/Database.js
CHANGED
|
@@ -168,9 +168,9 @@ export class DatabaseQuery extends Query {
|
|
|
168
168
|
}
|
|
169
169
|
/** Get the data for a document from a result for that document. */
|
|
170
170
|
export function getQueryData(entries, ref) {
|
|
171
|
-
const
|
|
172
|
-
if (
|
|
173
|
-
return
|
|
171
|
+
const data = getQueryResult(entries, ref);
|
|
172
|
+
if (data)
|
|
173
|
+
return data;
|
|
174
174
|
throw new QueryRequiredError(ref);
|
|
175
175
|
}
|
|
176
176
|
/** Get the data for a document from a result for that document. */
|
|
@@ -178,7 +178,7 @@ export function getQueryResult(entries, ref) {
|
|
|
178
178
|
const first = getFirstItem(entries);
|
|
179
179
|
if (first)
|
|
180
180
|
return getDocumentData(first[1], ref.doc(first[0]));
|
|
181
|
-
|
|
181
|
+
return null;
|
|
182
182
|
}
|
|
183
183
|
/** A document reference within a specific database. */
|
|
184
184
|
export class DatabaseDocument {
|
package/db/errors.d.ts
CHANGED
|
@@ -7,16 +7,40 @@ export declare class DocumentRequiredError<T extends Data> extends RequiredError
|
|
|
7
7
|
ref: DatabaseDocument<T>;
|
|
8
8
|
constructor(ref: DatabaseDocument<T>);
|
|
9
9
|
}
|
|
10
|
-
/** Thrown if
|
|
11
|
-
export declare class
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
/** Thrown if an error occurs while reading a document. */
|
|
11
|
+
export declare class DocumentReadError<T extends Data> extends Error {
|
|
12
|
+
error: Error;
|
|
13
|
+
ref: DatabaseDocument<T>;
|
|
14
|
+
constructor(error: Error, ref: DatabaseDocument<T>);
|
|
15
|
+
}
|
|
16
|
+
/** Thrown if an error occurs while writing a document. */
|
|
17
|
+
export declare class DocumentWriteError<T extends Data> extends Error {
|
|
18
|
+
error: Error;
|
|
19
|
+
ref: DatabaseDocument<T>;
|
|
20
|
+
constructor(error: Error, ref: DatabaseDocument<T>);
|
|
14
21
|
}
|
|
15
22
|
/** Thrown if a document can't validate. */
|
|
16
23
|
export declare class DocumentValidationError<T extends Data> extends ValidationError {
|
|
17
24
|
ref: DatabaseDocument<T>;
|
|
18
25
|
constructor(ref: DatabaseDocument<T>, feedback: Feedback);
|
|
19
26
|
}
|
|
27
|
+
/** Thrown if a query doesn't exist. */
|
|
28
|
+
export declare class QueryRequiredError<T extends Data> extends RequiredError {
|
|
29
|
+
ref: DatabaseQuery<T>;
|
|
30
|
+
constructor(ref: DatabaseQuery<T>);
|
|
31
|
+
}
|
|
32
|
+
/** Thrown if an error occurs while reading a query. */
|
|
33
|
+
export declare class QueryReadError<T extends Data> extends Error {
|
|
34
|
+
error: Error;
|
|
35
|
+
ref: DatabaseQuery<T>;
|
|
36
|
+
constructor(error: Error, ref: DatabaseQuery<T>);
|
|
37
|
+
}
|
|
38
|
+
/** Thrown if an error occurs while writing a query. */
|
|
39
|
+
export declare class QueryWriteError<T extends Data> extends Error {
|
|
40
|
+
error: Error;
|
|
41
|
+
ref: DatabaseQuery<T>;
|
|
42
|
+
constructor(error: Error, ref: DatabaseQuery<T>);
|
|
43
|
+
}
|
|
20
44
|
/** Thrown if a query can't validate a set of results. */
|
|
21
45
|
export declare class QueryValidationError<T extends Data> extends ValidationError {
|
|
22
46
|
ref: DatabaseQuery<T>;
|
package/db/errors.js
CHANGED
|
@@ -2,27 +2,63 @@ import { RequiredError, ValidationError } from "../error/index.js";
|
|
|
2
2
|
/** Thrown if a document doesn't exist. */
|
|
3
3
|
export class DocumentRequiredError extends RequiredError {
|
|
4
4
|
constructor(ref) {
|
|
5
|
-
super(`Document
|
|
5
|
+
super(`Document ${ref.toString()} does not exist`);
|
|
6
6
|
this.ref = ref;
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
DocumentRequiredError.prototype.name = "DocumentRequiredError";
|
|
10
|
-
/** Thrown if
|
|
11
|
-
export class
|
|
12
|
-
constructor(ref) {
|
|
13
|
-
super(`
|
|
10
|
+
/** Thrown if an error occurs while reading a document. */
|
|
11
|
+
export class DocumentReadError extends Error {
|
|
12
|
+
constructor(error, ref) {
|
|
13
|
+
super(`Error reading document ${ref.toString()}:\n${error.message}`);
|
|
14
|
+
this.error = error;
|
|
14
15
|
this.ref = ref;
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
+
DocumentReadError.prototype.name = "DocumentReadError";
|
|
19
|
+
/** Thrown if an error occurs while writing a document. */
|
|
20
|
+
export class DocumentWriteError extends Error {
|
|
21
|
+
constructor(error, ref) {
|
|
22
|
+
super(`Error writing document ${ref.toString()}:\n${error.message}`);
|
|
23
|
+
this.error = error;
|
|
24
|
+
this.ref = ref;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
DocumentWriteError.prototype.name = "DocumentWriteError";
|
|
18
28
|
/** Thrown if a document can't validate. */
|
|
19
29
|
export class DocumentValidationError extends ValidationError {
|
|
20
30
|
constructor(ref, feedback) {
|
|
21
|
-
super(`Invalid data for
|
|
31
|
+
super(`Invalid data for ${ref.toString()}`, feedback);
|
|
22
32
|
this.ref = ref;
|
|
23
33
|
}
|
|
24
34
|
}
|
|
25
35
|
DocumentValidationError.prototype.name = "DocumentValidationError";
|
|
36
|
+
/** Thrown if a query doesn't exist. */
|
|
37
|
+
export class QueryRequiredError extends RequiredError {
|
|
38
|
+
constructor(ref) {
|
|
39
|
+
super(`Query ${ref.toString()} has no results`);
|
|
40
|
+
this.ref = ref;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
QueryRequiredError.prototype.name = "QueryRequiredError";
|
|
44
|
+
/** Thrown if an error occurs while reading a query. */
|
|
45
|
+
export class QueryReadError extends Error {
|
|
46
|
+
constructor(error, ref) {
|
|
47
|
+
super(`Error reading query ${ref.toString()}:\n${error.message}`);
|
|
48
|
+
this.error = error;
|
|
49
|
+
this.ref = ref;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
QueryReadError.prototype.name = "QueryReadError";
|
|
53
|
+
/** Thrown if an error occurs while writing a query. */
|
|
54
|
+
export class QueryWriteError extends Error {
|
|
55
|
+
constructor(error, ref) {
|
|
56
|
+
super(`Error writing query ${ref.toString()}:\n${error.message}`);
|
|
57
|
+
this.error = error;
|
|
58
|
+
this.ref = ref;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
DocumentWriteError.prototype.name = "DocumentWriteError";
|
|
26
62
|
/** Thrown if a query can't validate a set of results. */
|
|
27
63
|
export class QueryValidationError extends ValidationError {
|
|
28
64
|
constructor(ref, feedback) {
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"state-management",
|
|
12
12
|
"query-builder"
|
|
13
13
|
],
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.52.0",
|
|
15
15
|
"repository": "https://github.com/dhoulb/shelving",
|
|
16
16
|
"author": "Dave Houlbrooke <dave@shax.com>",
|
|
17
17
|
"license": "0BSD",
|
|
@@ -63,13 +63,13 @@
|
|
|
63
63
|
"@types/jest": "^27.4.0",
|
|
64
64
|
"@types/react": "^17.0.39",
|
|
65
65
|
"@types/react-dom": "^17.0.11",
|
|
66
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
67
|
-
"@typescript-eslint/parser": "^5.
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^5.12.0",
|
|
67
|
+
"@typescript-eslint/parser": "^5.12.0",
|
|
68
68
|
"eslint": "^8.9.0",
|
|
69
|
-
"eslint-config-prettier": "^8.
|
|
69
|
+
"eslint-config-prettier": "^8.4.0",
|
|
70
70
|
"eslint-plugin-import": "^2.25.4",
|
|
71
71
|
"eslint-plugin-prettier": "^4.0.0",
|
|
72
|
-
"firebase": "^9.6.
|
|
72
|
+
"firebase": "^9.6.7",
|
|
73
73
|
"jest": "^27.5.1",
|
|
74
74
|
"jest-ts-webcompat-resolver": "^1.0.0",
|
|
75
75
|
"prettier": "^2.5.1",
|
package/query/Query.js
CHANGED
package/query/Rules.js
CHANGED
|
@@ -19,7 +19,7 @@ export class Rules extends Rule {
|
|
|
19
19
|
return this._rules.length;
|
|
20
20
|
}
|
|
21
21
|
toString() {
|
|
22
|
-
return this._rules.map(toString).join("
|
|
22
|
+
return this._rules.map(toString).join(",");
|
|
23
23
|
}
|
|
24
24
|
/** Clone this set of rules but add additional rules. */
|
|
25
25
|
with(...rules) {
|
package/react/useDocument.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { CacheProvider, throwAsync, NOERROR, findSourceProvider, NOVALUE, callAsync, getDocumentData } from "../index.js";
|
|
2
|
+
import { CacheProvider, throwAsync, NOERROR, findSourceProvider, NOVALUE, callAsync, getDocumentData, isAsync } from "../index.js";
|
|
3
3
|
import { usePureEffect } from "./usePureEffect.js";
|
|
4
4
|
import { usePureMemo } from "./usePureMemo.js";
|
|
5
5
|
import { usePureState } from "./usePureState.js";
|
|
@@ -9,13 +9,14 @@ export function useAsyncDocument(ref, maxAge = 1000) {
|
|
|
9
9
|
// Create two states to hold the value and error.
|
|
10
10
|
const [value, setNext] = usePureState(getCachedResult, memoRef);
|
|
11
11
|
const [error, setError] = useState(NOERROR);
|
|
12
|
-
if (error !== NOERROR)
|
|
13
|
-
throw error; // If there's an error throw it.
|
|
14
12
|
// Register effect.
|
|
15
13
|
usePureEffect(subscribeEffect, memoRef, maxAge, setNext, setError);
|
|
16
14
|
// Always return undefined if there's no ref.
|
|
17
15
|
if (!ref)
|
|
18
16
|
return undefined;
|
|
17
|
+
// If there's an error throw it.
|
|
18
|
+
if (error !== NOERROR)
|
|
19
|
+
throw error;
|
|
19
20
|
// If document is cached return the cached value.
|
|
20
21
|
if (value !== NOVALUE)
|
|
21
22
|
return value;
|
|
@@ -24,7 +25,10 @@ export function useAsyncDocument(ref, maxAge = 1000) {
|
|
|
24
25
|
if (maxAge === true)
|
|
25
26
|
setTimeout(ref.subscribe({ next: setNext, error: setError }), 10000);
|
|
26
27
|
// Return a promise for the result.
|
|
27
|
-
|
|
28
|
+
const result = ref.result;
|
|
29
|
+
if (isAsync(result))
|
|
30
|
+
result.then(setNext, setError);
|
|
31
|
+
return result;
|
|
28
32
|
}
|
|
29
33
|
/** Get the initial result for a reference from the cache. */
|
|
30
34
|
function getCachedResult(ref) {
|
|
@@ -34,22 +38,30 @@ function getCachedResult(ref) {
|
|
|
34
38
|
return provider.isCached(ref) ? provider.cache.get(ref) : NOVALUE;
|
|
35
39
|
}
|
|
36
40
|
/** Effect that subscribes a component to the cache for a reference. */
|
|
37
|
-
function subscribeEffect(ref, maxAge,
|
|
41
|
+
function subscribeEffect(ref, maxAge, setNext, setError) {
|
|
38
42
|
if (ref) {
|
|
39
43
|
const provider = findSourceProvider(ref.db.provider, CacheProvider);
|
|
40
|
-
const stopCache = provider.cache.subscribe(ref, { next, error });
|
|
44
|
+
const stopCache = provider.cache.subscribe(ref, { next: setNext, error: setError });
|
|
41
45
|
if (maxAge === true) {
|
|
42
46
|
// If `maxAge` is true subscribe to the source for as long as this component is attached.
|
|
43
|
-
const stopSource = ref.subscribe({ next, error });
|
|
47
|
+
const stopSource = ref.subscribe({ next: setNext, error: setError });
|
|
44
48
|
return () => {
|
|
45
49
|
stopCache();
|
|
46
50
|
stopSource();
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
|
-
else {
|
|
53
|
+
else if (provider.getCachedAge(ref) > maxAge) {
|
|
50
54
|
// If cache provider's cached document is older than maxAge then force refresh the data.
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
try {
|
|
56
|
+
const result = ref.result;
|
|
57
|
+
if (isAsync(result))
|
|
58
|
+
result.then(setNext, setError);
|
|
59
|
+
else
|
|
60
|
+
setNext(result);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
setError(e);
|
|
64
|
+
}
|
|
53
65
|
}
|
|
54
66
|
return stopCache;
|
|
55
67
|
}
|
package/react/useQuery.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { CacheProvider, NOERROR, findSourceProvider, NOVALUE, getMap, callAsync, getQueryData, throwAsync, ResultsObserver, getQueryResult, } from "../index.js";
|
|
2
|
+
import { CacheProvider, NOERROR, findSourceProvider, NOVALUE, getMap, callAsync, getQueryData, throwAsync, ResultsObserver, getQueryResult, isAsync, } from "../index.js";
|
|
3
3
|
import { usePureEffect } from "./usePureEffect.js";
|
|
4
4
|
import { usePureMemo } from "./usePureMemo.js";
|
|
5
5
|
import { usePureState } from "./usePureState.js";
|
|
@@ -24,7 +24,10 @@ export function useAsyncQuery(ref, maxAge = 1000) {
|
|
|
24
24
|
if (maxAge === true)
|
|
25
25
|
setTimeout(ref.subscribe({ next: setNext, error: setError }), 10000);
|
|
26
26
|
// Return a promise for the result.
|
|
27
|
-
|
|
27
|
+
const results = ref.results;
|
|
28
|
+
if (isAsync(results))
|
|
29
|
+
results.then(setNext, setError);
|
|
30
|
+
return results;
|
|
28
31
|
}
|
|
29
32
|
/** Get the initial results for a reference from the cache. */
|
|
30
33
|
function getCachedResults(ref) {
|
|
@@ -34,10 +37,10 @@ function getCachedResults(ref) {
|
|
|
34
37
|
return provider.isCached(ref) ? getMap(provider.cache.getQuery(ref)) : NOVALUE;
|
|
35
38
|
}
|
|
36
39
|
/** Effect that subscribes a component to the cache for a reference. */
|
|
37
|
-
function subscribeEffect(ref, maxAge,
|
|
40
|
+
function subscribeEffect(ref, maxAge, setNext, setError) {
|
|
38
41
|
if (ref) {
|
|
39
42
|
const provider = findSourceProvider(ref.db.provider, CacheProvider);
|
|
40
|
-
const observer = new ResultsObserver({ next, error });
|
|
43
|
+
const observer = new ResultsObserver({ next: setNext, error: setError });
|
|
41
44
|
const stopCache = provider.cache.subscribeQuery(ref, observer);
|
|
42
45
|
if (maxAge === true) {
|
|
43
46
|
// If `maxAge` is true subscribe to the source for as long as this component is attached.
|
|
@@ -47,10 +50,19 @@ function subscribeEffect(ref, maxAge, next, error) {
|
|
|
47
50
|
stopSource();
|
|
48
51
|
};
|
|
49
52
|
}
|
|
50
|
-
else {
|
|
53
|
+
else if (provider.getCachedAge(ref) > maxAge) {
|
|
51
54
|
// If cache provider's cached document is older than maxAge then force refresh the data.
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
Promise.resolve(ref.results).then(setNext, setError);
|
|
56
|
+
try {
|
|
57
|
+
const results = ref.results;
|
|
58
|
+
if (isAsync(results))
|
|
59
|
+
results.then(setNext, setError);
|
|
60
|
+
else
|
|
61
|
+
setNext(results);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
setError(e);
|
|
65
|
+
}
|
|
54
66
|
}
|
|
55
67
|
return stopCache;
|
|
56
68
|
}
|
package/util/jsx.d.ts
CHANGED
|
@@ -7,8 +7,8 @@ export declare type JSXProps = {
|
|
|
7
7
|
readonly children?: JSXNode;
|
|
8
8
|
};
|
|
9
9
|
/** JSX element (similar to `React.ReactElement`) */
|
|
10
|
-
export declare type JSXElement<P extends JSXProps = JSXProps
|
|
11
|
-
type:
|
|
10
|
+
export declare type JSXElement<P extends JSXProps = JSXProps> = {
|
|
11
|
+
type: string | JSXElementCreator<P>;
|
|
12
12
|
props: P;
|
|
13
13
|
key: string | number | null;
|
|
14
14
|
$$typeof?: symbol;
|