@verdant-web/store 5.4.0 → 5.4.3
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/dist/bundle/index.js +8 -8
- package/dist/bundle/index.js.map +4 -4
- package/dist/esm/__tests__/queries.test.js +16 -0
- package/dist/esm/__tests__/queries.test.js.map +1 -1
- package/dist/esm/client/Client.js +12 -4
- package/dist/esm/client/Client.js.map +1 -1
- package/dist/esm/entities/Entity.d.ts +2 -5
- package/dist/esm/entities/Entity.js +17 -10
- package/dist/esm/entities/Entity.js.map +1 -1
- package/dist/esm/entities/EntityMetadata.js +14 -2
- package/dist/esm/entities/EntityMetadata.js.map +1 -1
- package/dist/esm/entities/EntityStore.js +1 -0
- package/dist/esm/entities/EntityStore.js.map +1 -1
- package/dist/esm/persistence/MessageCreator.js +1 -1
- package/dist/esm/persistence/MessageCreator.js.map +1 -1
- package/dist/esm/persistence/PersistenceMetadata.d.ts +6 -1
- package/dist/esm/persistence/PersistenceMetadata.js +40 -2
- package/dist/esm/persistence/PersistenceMetadata.js.map +1 -1
- package/dist/esm/persistence/PersistenceRebaser.js +1 -1
- package/dist/esm/persistence/PersistenceRebaser.js.map +1 -1
- package/dist/esm/persistence/idb/IdbService.js +1 -1
- package/dist/esm/persistence/idb/IdbService.js.map +1 -1
- package/dist/esm/persistence/idb/indexNames.d.ts +5 -0
- package/dist/esm/persistence/idb/indexNames.js +6 -0
- package/dist/esm/persistence/idb/indexNames.js.map +1 -0
- package/dist/esm/persistence/idb/metadata/IdbMetadataDb.d.ts +6 -3
- package/dist/esm/persistence/idb/metadata/IdbMetadataDb.js +33 -8
- package/dist/esm/persistence/idb/metadata/IdbMetadataDb.js.map +1 -1
- package/dist/esm/persistence/idb/metadata/openMetadataDatabase.js +5 -5
- package/dist/esm/persistence/idb/metadata/openMetadataDatabase.js.map +1 -1
- package/dist/esm/persistence/idb/queries/ranges.js +3 -4
- package/dist/esm/persistence/idb/queries/ranges.js.map +1 -1
- package/dist/esm/persistence/interfaces.d.ts +2 -0
- package/dist/esm/persistence/migration/engine.js +3 -4
- package/dist/esm/persistence/migration/engine.js.map +1 -1
- package/dist/esm/queries/BaseQuery.d.ts +8 -0
- package/dist/esm/queries/BaseQuery.js +49 -5
- package/dist/esm/queries/BaseQuery.js.map +1 -1
- package/dist/esm/queries/FindAllQuery.js +3 -3
- package/dist/esm/queries/FindAllQuery.js.map +1 -1
- package/dist/esm/queries/FindInfiniteQuery.js +6 -6
- package/dist/esm/queries/FindInfiniteQuery.js.map +1 -1
- package/dist/esm/queries/FindOneQuery.js +3 -3
- package/dist/esm/queries/FindOneQuery.js.map +1 -1
- package/dist/esm/queries/FindPageQuery.js +3 -3
- package/dist/esm/queries/FindPageQuery.js.map +1 -1
- package/dist/esm/queries/GetQuery.js +1 -1
- package/dist/esm/queries/GetQuery.js.map +1 -1
- package/dist/esm/queries/QueryCache.d.ts +4 -1
- package/dist/esm/queries/QueryCache.js +15 -1
- package/dist/esm/queries/QueryCache.js.map +1 -1
- package/dist/esm/queries/diagnostics.d.ts +24 -0
- package/dist/esm/queries/diagnostics.js +11 -0
- package/dist/esm/queries/diagnostics.js.map +1 -0
- package/dist/esm/queries/ranges.js +3 -4
- package/dist/esm/queries/ranges.js.map +1 -1
- package/dist/esm/sync/WebSocketSync.js +4 -2
- package/dist/esm/sync/WebSocketSync.js.map +1 -1
- package/package.json +7 -2
- package/src/__tests__/queries.test.ts +19 -0
- package/src/client/Client.ts +15 -4
- package/src/entities/Entity.ts +31 -22
- package/src/entities/EntityMetadata.ts +15 -3
- package/src/entities/EntityStore.ts +1 -0
- package/src/persistence/MessageCreator.ts +1 -1
- package/src/persistence/PersistenceMetadata.ts +67 -7
- package/src/persistence/PersistenceRebaser.ts +1 -1
- package/src/persistence/idb/IdbService.ts +1 -1
- package/src/persistence/idb/indexNames.ts +5 -0
- package/src/persistence/idb/metadata/IdbMetadataDb.ts +71 -14
- package/src/persistence/idb/metadata/openMetadataDatabase.ts +15 -7
- package/src/persistence/idb/queries/ranges.ts +2 -3
- package/src/persistence/interfaces.ts +5 -1
- package/src/persistence/migration/engine.ts +3 -4
- package/src/queries/BaseQuery.ts +56 -10
- package/src/queries/FindAllQuery.ts +10 -8
- package/src/queries/FindInfiniteQuery.ts +22 -18
- package/src/queries/FindOneQuery.ts +9 -7
- package/src/queries/FindPageQuery.ts +11 -9
- package/src/queries/GetQuery.ts +1 -1
- package/src/queries/QueryCache.ts +19 -2
- package/src/queries/diagnostics.ts +38 -0
- package/src/queries/ranges.ts +2 -3
- package/src/sync/WebSocketSync.ts +2 -0
|
@@ -27,18 +27,20 @@ export class FindAllQuery<T> extends BaseQuery<T[]> {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
protected run = async () => {
|
|
30
|
-
const { result: oids } = await (
|
|
31
|
-
await this.context.documents
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
const { result: oids } = await this.measureSweep(async () =>
|
|
31
|
+
(await this.context.documents).findAllOids({
|
|
32
|
+
collection: this.collection,
|
|
33
|
+
index: this.index,
|
|
34
|
+
limit: this.limit,
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
37
|
this.context.log(
|
|
38
38
|
'debug',
|
|
39
39
|
`FindAllQuery: ${oids.length} oids found: ${oids}`,
|
|
40
40
|
);
|
|
41
|
-
this.setValue(
|
|
41
|
+
this.setValue(
|
|
42
|
+
await this.measureHydration(() => Promise.all(oids.map(this.hydrate))),
|
|
43
|
+
);
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
[UPDATE] = (index: CollectionFilter | undefined) => {
|
|
@@ -37,32 +37,36 @@ export class FindInfiniteQuery<T> extends BaseQuery<T[]> {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
protected run = async () => {
|
|
40
|
-
const { result, hasNextPage } = await (
|
|
41
|
-
await this.context.documents
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
const { result, hasNextPage } = await this.measureSweep(async () =>
|
|
41
|
+
(await this.context.documents).findAllOids({
|
|
42
|
+
collection: this.collection,
|
|
43
|
+
limit: this._pageSize * this._upToPage,
|
|
44
|
+
offset: 0,
|
|
45
|
+
index: this.index,
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
48
|
this._hasNextPage = hasNextPage;
|
|
49
|
-
this.setValue(
|
|
49
|
+
this.setValue(
|
|
50
|
+
await this.measureHydration(() => Promise.all(result.map(this.hydrate))),
|
|
51
|
+
);
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
public loadMore = async () => {
|
|
53
|
-
const { result, hasNextPage } = await (
|
|
54
|
-
await this.context.documents
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
const { result, hasNextPage } = await this.measureSweep(async () =>
|
|
56
|
+
(await this.context.documents).findAllOids({
|
|
57
|
+
collection: this.collection,
|
|
58
|
+
limit: this._pageSize,
|
|
59
|
+
offset: this._pageSize * this._upToPage,
|
|
60
|
+
index: this.index,
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
61
63
|
this._hasNextPage = hasNextPage;
|
|
62
64
|
this._upToPage++;
|
|
63
65
|
this.setValue([
|
|
64
66
|
...this.current,
|
|
65
|
-
...(await
|
|
67
|
+
...(await this.measureHydration(() =>
|
|
68
|
+
Promise.all(result.map(this.hydrate)),
|
|
69
|
+
)),
|
|
66
70
|
]);
|
|
67
71
|
};
|
|
68
72
|
|
|
@@ -23,13 +23,15 @@ export class FindOneQuery<T> extends BaseQuery<T | null> {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
protected run = async () => {
|
|
26
|
-
const oid = await (
|
|
27
|
-
await this.context.documents
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.setValue(
|
|
26
|
+
const oid = await this.measureSweep(async () =>
|
|
27
|
+
(await this.context.documents).findOneOid({
|
|
28
|
+
collection: this.collection,
|
|
29
|
+
index: this.index,
|
|
30
|
+
}),
|
|
31
|
+
);
|
|
32
|
+
this.setValue(
|
|
33
|
+
oid ? await this.measureHydration(() => this.hydrate(oid)) : null,
|
|
34
|
+
);
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
[UPDATE] = (index: CollectionFilter | undefined) => {
|
|
@@ -48,16 +48,18 @@ export class FindPageQuery<T> extends BaseQuery<T[]> {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
protected run = async () => {
|
|
51
|
-
const { result, hasNextPage } = await (
|
|
52
|
-
await this.context.documents
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
const { result, hasNextPage } = await this.measureSweep(async () =>
|
|
52
|
+
(await this.context.documents).findAllOids({
|
|
53
|
+
collection: this.collection,
|
|
54
|
+
index: this.index,
|
|
55
|
+
limit: this._pageSize,
|
|
56
|
+
offset: this._page * this._pageSize,
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
59
|
this._hasNextPage = hasNextPage;
|
|
60
|
-
this.setValue(
|
|
60
|
+
this.setValue(
|
|
61
|
+
await this.measureHydration(() => Promise.all(result.map(this.hydrate))),
|
|
62
|
+
);
|
|
61
63
|
};
|
|
62
64
|
|
|
63
65
|
nextPage = async () => {
|
package/src/queries/GetQuery.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Context } from '../context/context.js';
|
|
2
2
|
import { Disposable } from '../utils/Disposable.js';
|
|
3
3
|
import { BaseQuery, ON_ALL_UNSUBSCRIBED } from './BaseQuery.js';
|
|
4
|
+
import { QueryDiagnostic, QueryDiagnostics } from './diagnostics.js';
|
|
4
5
|
|
|
5
6
|
export class QueryCache extends Disposable {
|
|
6
7
|
private _cache: Map<string, BaseQuery<any>> = new Map();
|
|
@@ -8,6 +9,7 @@ export class QueryCache extends Disposable {
|
|
|
8
9
|
private context;
|
|
9
10
|
/** A set of query keys to keep alive even if they unsubscribe */
|
|
10
11
|
private _holds = new Set<string>();
|
|
12
|
+
private _inactiveDiagnostics = new Map<string, QueryDiagnostic>();
|
|
11
13
|
|
|
12
14
|
constructor({
|
|
13
15
|
evictionTime = 5 * 1000,
|
|
@@ -38,6 +40,7 @@ export class QueryCache extends Disposable {
|
|
|
38
40
|
|
|
39
41
|
set<V extends BaseQuery<any>>(value: V) {
|
|
40
42
|
this._cache.set(value.key, value);
|
|
43
|
+
this._inactiveDiagnostics.delete(value.key);
|
|
41
44
|
value[ON_ALL_UNSUBSCRIBED](this.enqueueQueryEviction);
|
|
42
45
|
// immediately enqueue a check to see if this query should be evicted --
|
|
43
46
|
// this basically gives code X seconds to subscribe to the query before
|
|
@@ -47,6 +50,15 @@ export class QueryCache extends Disposable {
|
|
|
47
50
|
return value;
|
|
48
51
|
}
|
|
49
52
|
|
|
53
|
+
get diagnostics(): QueryDiagnostics {
|
|
54
|
+
return {
|
|
55
|
+
queries: [
|
|
56
|
+
...this._cache.values().map((query) => query.getDiagnostic(true)),
|
|
57
|
+
...this._inactiveDiagnostics.values(),
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
50
62
|
getOrSet<V extends BaseQuery<any>>(
|
|
51
63
|
key: string,
|
|
52
64
|
create: () => V,
|
|
@@ -78,19 +90,23 @@ export class QueryCache extends Disposable {
|
|
|
78
90
|
// got a different version of this query.
|
|
79
91
|
if (this._cache.get(query.key) === query) {
|
|
80
92
|
this._cache.delete(query.key);
|
|
93
|
+
this._inactiveDiagnostics.set(query.key, query.getDiagnostic(false));
|
|
81
94
|
this.context.log('debug', 'QueryCache: evicted query', query.key);
|
|
82
95
|
}
|
|
83
96
|
}, this._evictionTime);
|
|
84
97
|
};
|
|
85
98
|
|
|
86
|
-
|
|
99
|
+
dropAll = () => {
|
|
87
100
|
this.context.log(
|
|
88
101
|
'debug',
|
|
89
102
|
'QueryCache: drop all',
|
|
90
103
|
this._cache.size,
|
|
91
104
|
'queries',
|
|
92
105
|
);
|
|
93
|
-
this._cache.forEach((query) =>
|
|
106
|
+
this._cache.forEach((query) => {
|
|
107
|
+
this._inactiveDiagnostics.set(query.key, query.getDiagnostic(false));
|
|
108
|
+
query.dispose();
|
|
109
|
+
});
|
|
94
110
|
this._cache.clear();
|
|
95
111
|
};
|
|
96
112
|
|
|
@@ -135,4 +151,5 @@ export type PublicQueryCacheAPI = Pick<
|
|
|
135
151
|
| 'keepAlives'
|
|
136
152
|
| 'forceRefreshAll'
|
|
137
153
|
| 'activeKeys'
|
|
154
|
+
| 'diagnostics'
|
|
138
155
|
>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Entity } from '../entities/Entity.js';
|
|
2
|
+
import type { QueryStatus } from './BaseQuery.js';
|
|
3
|
+
|
|
4
|
+
export type QueryTiming = {
|
|
5
|
+
sweep: number | null;
|
|
6
|
+
hydration: number | null;
|
|
7
|
+
total: number | null;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type QueryRun = QueryTiming & {
|
|
11
|
+
startedAt: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type QueryDiagnostic = {
|
|
15
|
+
key: string;
|
|
16
|
+
startedAt: number | null;
|
|
17
|
+
collection: string;
|
|
18
|
+
type: string;
|
|
19
|
+
status: QueryStatus;
|
|
20
|
+
active: boolean;
|
|
21
|
+
result: unknown;
|
|
22
|
+
timing: QueryTiming;
|
|
23
|
+
runs: QueryRun[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type QueryDiagnostics = {
|
|
27
|
+
queries: QueryDiagnostic[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const getDiagnosticResult = (value: unknown): unknown => {
|
|
31
|
+
if (Array.isArray(value)) {
|
|
32
|
+
return value.map(getDiagnosticResult);
|
|
33
|
+
}
|
|
34
|
+
if (value instanceof Entity) {
|
|
35
|
+
return value.getSnapshot();
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
};
|
package/src/queries/ranges.ts
CHANGED
|
@@ -46,15 +46,14 @@ const rangeIndexToIdbKeyRange = (filter: RangeCollectionIndexFilter) => {
|
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
const compoundIndexToIdbKeyRange = (
|
|
49
|
-
|
|
50
|
-
schema: any,
|
|
49
|
+
schema: StorageSchema,
|
|
51
50
|
collection: string,
|
|
52
51
|
filter: CollectionCompoundIndexFilter,
|
|
53
52
|
) => {
|
|
54
53
|
// validate the usage of the compound index:
|
|
55
54
|
// - all match fields must be contiguous at the start of the compound order
|
|
56
55
|
const indexDefinition =
|
|
57
|
-
schema.collections[collection].compounds[filter.where];
|
|
56
|
+
schema.collections[collection].compounds?.[filter.where];
|
|
58
57
|
assert(
|
|
59
58
|
indexDefinition,
|
|
60
59
|
`Index ${filter.where} does not exist on collection ${collection}`,
|
|
@@ -314,6 +314,8 @@ export class WebSocketSync
|
|
|
314
314
|
await this.sendDisconnecting();
|
|
315
315
|
this.socket?.removeEventListener('message', this.onMessage);
|
|
316
316
|
this.socket?.removeEventListener('close', this.onClose);
|
|
317
|
+
this.socket?.removeEventListener('error', this.onError);
|
|
318
|
+
this.socket?.removeEventListener('open', this.onOpen);
|
|
317
319
|
if (this.socket?.readyState === WEBSOCKET_OPEN) {
|
|
318
320
|
this.socket.close();
|
|
319
321
|
}
|