@veams/status-quo-query 0.9.0 → 0.10.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/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/query-registry.d.ts +9 -0
- package/dist/query-registry.js +28 -0
- package/dist/query-registry.js.map +1 -0
- package/package.json +8 -1
- package/src/__tests__/query-registry.spec.ts +101 -0
- package/src/index.ts +2 -0
- package/src/query-registry.ts +52 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './mutation.js';
|
|
2
2
|
export * from './query.js';
|
|
3
3
|
export * from './provider.js';
|
|
4
|
+
export * from './query-registry.js';
|
|
4
5
|
export type { TrackedDependencyRecord, TrackedDependencyValue, TrackedInvalidateOn, TrackedMatchMode, TrackedQueryKey, TrackedQueryKeySegment, } from './tracking.js';
|
package/dist/index.js
CHANGED
|
@@ -4,4 +4,6 @@ export * from './mutation.js';
|
|
|
4
4
|
export * from './query.js';
|
|
5
5
|
// Re-export all provider-related types and functions for cache management.
|
|
6
6
|
export * from './provider.js';
|
|
7
|
+
// Re-export query registry helpers for memoizing query services by key.
|
|
8
|
+
export * from './query-registry.js';
|
|
7
9
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,cAAc,eAAe,CAAC;AAC9B,mDAAmD;AACnD,cAAc,YAAY,CAAC;AAC3B,2EAA2E;AAC3E,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,cAAc,eAAe,CAAC;AAC9B,mDAAmD;AACnD,cAAc,YAAY,CAAC;AAC3B,2EAA2E;AAC3E,cAAc,eAAe,CAAC;AAC9B,wEAAwE;AACxE,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { QueryService } from './query.js';
|
|
2
|
+
export interface QueryRegistry<TParams, TKey extends readonly unknown[]> {
|
|
3
|
+
clear: () => void;
|
|
4
|
+
getKey: (params: TParams) => TKey;
|
|
5
|
+
name: string;
|
|
6
|
+
resolve: <TData, TError = Error>(params: TParams, create: (queryKey: TKey) => QueryService<TData, TError>) => QueryService<TData, TError>;
|
|
7
|
+
}
|
|
8
|
+
export declare function createQueryRegistry<TParams, TKey extends readonly unknown[]>(name: string, createKey: (params: TParams) => TKey): QueryRegistry<TParams, TKey>;
|
|
9
|
+
export declare function serializeQueryKey(queryKey: readonly unknown[]): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { hashKey } from '@tanstack/query-core';
|
|
2
|
+
export function createQueryRegistry(name, createKey) {
|
|
3
|
+
const entries = new Map();
|
|
4
|
+
return {
|
|
5
|
+
name,
|
|
6
|
+
clear() {
|
|
7
|
+
entries.clear();
|
|
8
|
+
},
|
|
9
|
+
getKey(params) {
|
|
10
|
+
return createKey(params);
|
|
11
|
+
},
|
|
12
|
+
resolve(params, create) {
|
|
13
|
+
const queryKey = createKey(params);
|
|
14
|
+
const cacheKey = serializeQueryKey(queryKey);
|
|
15
|
+
const existingEntry = entries.get(cacheKey);
|
|
16
|
+
if (existingEntry) {
|
|
17
|
+
return existingEntry;
|
|
18
|
+
}
|
|
19
|
+
const nextEntry = create(queryKey);
|
|
20
|
+
entries.set(cacheKey, nextEntry);
|
|
21
|
+
return nextEntry;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function serializeQueryKey(queryKey) {
|
|
26
|
+
return hashKey(queryKey);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=query-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-registry.js","sourceRoot":"","sources":["../src/query-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAc/C,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,SAAoC;IAEpC,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0C,CAAC;IAElE,OAAO;QACL,IAAI;QACJ,KAAK;YACH,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QACD,MAAM,CAAC,MAAM;YACX,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,CACL,MAAe,EACf,MAAuD;YAEvD,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAC7C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAA4C,CAAC;YAEvF,IAAI,aAAa,EAAE,CAAC;gBAClB,OAAO,aAAa,CAAC;YACvB,CAAC;YAED,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAEnC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,SAA2C,CAAC,CAAC;YAEnE,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAA4B;IAC5D,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC3B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veams/status-quo-query",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "TanStack Query service layer for the VEAMS StatusQuo ecosystem.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -32,6 +32,13 @@
|
|
|
32
32
|
"default": "./dist/provider.js"
|
|
33
33
|
},
|
|
34
34
|
"require": "./dist/provider.js"
|
|
35
|
+
},
|
|
36
|
+
"./query-registry": {
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/query-registry.d.ts",
|
|
39
|
+
"default": "./dist/query-registry.js"
|
|
40
|
+
},
|
|
41
|
+
"require": "./dist/query-registry.js"
|
|
35
42
|
}
|
|
36
43
|
},
|
|
37
44
|
"types": "dist/index.d.ts",
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { QueryService } from '../query';
|
|
2
|
+
import { createQueryRegistry, serializeQueryKey } from '../query-registry';
|
|
3
|
+
|
|
4
|
+
describe('createQueryRegistry', () => {
|
|
5
|
+
it('reuses the same entry for identical params', () => {
|
|
6
|
+
const registry = createQueryRegistry('branches', (params: { branchId: string }) => [
|
|
7
|
+
'branch',
|
|
8
|
+
{
|
|
9
|
+
deps: {
|
|
10
|
+
branchId: params.branchId,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
] as const);
|
|
14
|
+
const createEntry = jest.fn((queryKey) => ({ queryKey }));
|
|
15
|
+
|
|
16
|
+
const firstEntry = registry.resolve({ branchId: 'branch-1' }, createEntry as never);
|
|
17
|
+
const secondEntry = registry.resolve({ branchId: 'branch-1' }, createEntry as never);
|
|
18
|
+
|
|
19
|
+
expect(firstEntry).toBe(secondEntry);
|
|
20
|
+
expect(createEntry).toHaveBeenCalledTimes(1);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('creates separate entries for different params', () => {
|
|
24
|
+
const registry = createQueryRegistry('branches', (params: { branchId: string }) => [
|
|
25
|
+
'branch',
|
|
26
|
+
{
|
|
27
|
+
deps: {
|
|
28
|
+
branchId: params.branchId,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
] as const);
|
|
32
|
+
const createEntry = jest.fn((queryKey) => ({ queryKey }));
|
|
33
|
+
|
|
34
|
+
const firstEntry = registry.resolve({ branchId: 'branch-1' }, createEntry as never);
|
|
35
|
+
const secondEntry = registry.resolve({ branchId: 'branch-2' }, createEntry as never);
|
|
36
|
+
|
|
37
|
+
expect(firstEntry).not.toBe(secondEntry);
|
|
38
|
+
expect(createEntry).toHaveBeenCalledTimes(2);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('exposes the generated query key', () => {
|
|
42
|
+
const registry = createQueryRegistry('branches', (params: { branchId: string }) => [
|
|
43
|
+
'branch',
|
|
44
|
+
{
|
|
45
|
+
deps: {
|
|
46
|
+
branchId: params.branchId,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
] as const);
|
|
50
|
+
|
|
51
|
+
expect(registry.getKey({ branchId: 'branch-1' })).toEqual([
|
|
52
|
+
'branch',
|
|
53
|
+
{
|
|
54
|
+
deps: {
|
|
55
|
+
branchId: 'branch-1',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('uses TanStack-compatible stable hashing for object keys', () => {
|
|
62
|
+
const firstKey = ['branch', { deps: { branchId: 'branch-1', companyId: 'company-1' } }] as const;
|
|
63
|
+
const secondKey = ['branch', { deps: { companyId: 'company-1', branchId: 'branch-1' } }] as const;
|
|
64
|
+
|
|
65
|
+
expect(serializeQueryKey(firstKey)).toBe(serializeQueryKey(secondKey));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('infers the query service type from the creator callback', () => {
|
|
69
|
+
const registry = createQueryRegistry('branches', (params: { branchId: string }) => [
|
|
70
|
+
'branch',
|
|
71
|
+
{
|
|
72
|
+
deps: {
|
|
73
|
+
branchId: params.branchId,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
] as const);
|
|
77
|
+
|
|
78
|
+
const query = registry.resolve({ branchId: 'branch-1' }, () => {
|
|
79
|
+
return {
|
|
80
|
+
getSnapshot: () => ({
|
|
81
|
+
data: { id: 'branch-1' },
|
|
82
|
+
error: null,
|
|
83
|
+
fetchStatus: 'idle',
|
|
84
|
+
isError: false,
|
|
85
|
+
isFetching: false,
|
|
86
|
+
isPending: false,
|
|
87
|
+
isSuccess: true,
|
|
88
|
+
status: 'success',
|
|
89
|
+
}),
|
|
90
|
+
invalidate: jest.fn(),
|
|
91
|
+
refetch: jest.fn(),
|
|
92
|
+
subscribe: jest.fn(),
|
|
93
|
+
unsafe_getResult: jest.fn(),
|
|
94
|
+
} as unknown as QueryService<{ id: string }, Error>;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const typedQuery: QueryService<{ id: string }, Error> = query;
|
|
98
|
+
|
|
99
|
+
expect(typedQuery).toBe(query);
|
|
100
|
+
});
|
|
101
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,8 @@ export * from './mutation.js';
|
|
|
4
4
|
export * from './query.js';
|
|
5
5
|
// Re-export all provider-related types and functions for cache management.
|
|
6
6
|
export * from './provider.js';
|
|
7
|
+
// Re-export query registry helpers for memoizing query services by key.
|
|
8
|
+
export * from './query-registry.js';
|
|
7
9
|
// Re-export tracked dependency types used by the additive tracked facade.
|
|
8
10
|
export type {
|
|
9
11
|
TrackedDependencyRecord,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { hashKey } from '@tanstack/query-core';
|
|
2
|
+
|
|
3
|
+
import type { QueryService } from './query.js';
|
|
4
|
+
|
|
5
|
+
export interface QueryRegistry<TParams, TKey extends readonly unknown[]> {
|
|
6
|
+
clear: () => void;
|
|
7
|
+
getKey: (params: TParams) => TKey;
|
|
8
|
+
name: string;
|
|
9
|
+
resolve: <TData, TError = Error>(
|
|
10
|
+
params: TParams,
|
|
11
|
+
create: (queryKey: TKey) => QueryService<TData, TError>
|
|
12
|
+
) => QueryService<TData, TError>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createQueryRegistry<TParams, TKey extends readonly unknown[]>(
|
|
16
|
+
name: string,
|
|
17
|
+
createKey: (params: TParams) => TKey
|
|
18
|
+
): QueryRegistry<TParams, TKey> {
|
|
19
|
+
const entries = new Map<string, QueryService<unknown, unknown>>();
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
name,
|
|
23
|
+
clear() {
|
|
24
|
+
entries.clear();
|
|
25
|
+
},
|
|
26
|
+
getKey(params) {
|
|
27
|
+
return createKey(params);
|
|
28
|
+
},
|
|
29
|
+
resolve<TData, TError = Error>(
|
|
30
|
+
params: TParams,
|
|
31
|
+
create: (queryKey: TKey) => QueryService<TData, TError>
|
|
32
|
+
) {
|
|
33
|
+
const queryKey = createKey(params);
|
|
34
|
+
const cacheKey = serializeQueryKey(queryKey);
|
|
35
|
+
const existingEntry = entries.get(cacheKey) as QueryService<TData, TError> | undefined;
|
|
36
|
+
|
|
37
|
+
if (existingEntry) {
|
|
38
|
+
return existingEntry;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const nextEntry = create(queryKey);
|
|
42
|
+
|
|
43
|
+
entries.set(cacheKey, nextEntry as QueryService<unknown, unknown>);
|
|
44
|
+
|
|
45
|
+
return nextEntry;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function serializeQueryKey(queryKey: readonly unknown[]): string {
|
|
51
|
+
return hashKey(queryKey);
|
|
52
|
+
}
|