houdini 1.0.0-next.4 → 1.0.0-next.6
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/build/cmd-cjs/index.js +1307 -1102
- package/build/cmd-esm/index.js +1307 -1102
- package/build/codegen/generators/artifacts/index.d.ts +2 -2
- package/build/codegen/generators/artifacts/indexFile.d.ts +2 -2
- package/build/codegen/generators/artifacts/selection.d.ts +2 -2
- package/build/codegen/generators/artifacts/utils.d.ts +0 -1
- package/build/codegen/generators/indexFile/index.d.ts +2 -2
- package/build/codegen/generators/persistedQueries/index.d.ts +2 -2
- package/build/codegen/generators/runtime/graphqlFunction.d.ts +2 -2
- package/build/codegen/generators/runtime/index.d.ts +2 -2
- package/build/codegen/generators/typescript/documentTypes.d.ts +2 -2
- package/build/codegen/generators/typescript/imperativeTypeDef.d.ts +2 -2
- package/build/codegen/generators/typescript/index.d.ts +2 -2
- package/build/codegen/index.d.ts +2 -2
- package/build/codegen/transforms/addID.d.ts +2 -2
- package/build/codegen/transforms/composeQueries.d.ts +4 -4
- package/build/codegen/transforms/fragmentVariables.d.ts +2 -2
- package/build/codegen/transforms/list.d.ts +2 -2
- package/build/codegen/transforms/paginate.d.ts +2 -2
- package/build/codegen/transforms/schema.d.ts +2 -2
- package/build/codegen/transforms/typename.d.ts +2 -2
- package/build/codegen/validators/noIDAlias.d.ts +2 -2
- package/build/codegen/validators/plugins.d.ts +2 -2
- package/build/codegen/validators/typeCheck.d.ts +2 -2
- package/build/codegen/validators/uniqueNames.d.ts +2 -2
- package/build/codegen-cjs/index.js +900 -757
- package/build/codegen-esm/index.js +900 -757
- package/build/lib/config.d.ts +10 -90
- package/build/lib/deepMerge.d.ts +1 -0
- package/build/lib/graphql.d.ts +5 -2
- package/build/lib/index.d.ts +2 -0
- package/build/lib/pipeline.d.ts +1 -1
- package/build/lib/plugin.d.ts +2 -0
- package/build/lib/types.d.ts +252 -4
- package/build/lib-cjs/index.js +351 -162
- package/build/lib-esm/index.js +349 -162
- package/build/runtime/cache/cache.d.ts +20 -3
- package/build/runtime/cache/staleManager.d.ts +30 -0
- package/build/runtime/cache/subscription.d.ts +2 -1
- package/build/runtime/client/plugins/subscription.d.ts +1 -2
- package/build/runtime/lib/config.d.ts +4 -0
- package/build/runtime/lib/index.d.ts +1 -0
- package/build/runtime/lib/key.d.ts +6 -0
- package/build/runtime/lib/types.d.ts +2 -2
- package/build/runtime/public/cache.d.ts +8 -1
- package/build/runtime/public/record.d.ts +11 -1
- package/build/runtime/public/tests/test.d.ts +9 -10
- package/build/runtime-cjs/cache/cache.d.ts +20 -3
- package/build/runtime-cjs/cache/cache.js +65 -6
- package/build/runtime-cjs/cache/gc.js +9 -0
- package/build/runtime-cjs/cache/staleManager.d.ts +30 -0
- package/build/runtime-cjs/cache/staleManager.js +95 -0
- package/build/runtime-cjs/cache/subscription.d.ts +2 -1
- package/build/runtime-cjs/cache/subscription.js +6 -3
- package/build/runtime-cjs/client/documentStore.js +1 -0
- package/build/runtime-cjs/client/plugins/cache.js +5 -3
- package/build/runtime-cjs/client/plugins/fetch.js +1 -0
- package/build/runtime-cjs/client/plugins/query.js +1 -0
- package/build/runtime-cjs/client/plugins/subscription.d.ts +1 -2
- package/build/runtime-cjs/client/plugins/subscription.js +2 -0
- package/build/runtime-cjs/lib/config.d.ts +4 -0
- package/build/runtime-cjs/lib/index.d.ts +1 -0
- package/build/runtime-cjs/lib/index.js +1 -0
- package/build/runtime-cjs/lib/key.d.ts +6 -0
- package/build/runtime-cjs/lib/key.js +41 -0
- package/build/runtime-cjs/lib/types.d.ts +2 -2
- package/build/runtime-cjs/public/cache.d.ts +8 -1
- package/build/runtime-cjs/public/cache.js +3 -0
- package/build/runtime-cjs/public/record.d.ts +11 -1
- package/build/runtime-cjs/public/record.js +8 -1
- package/build/runtime-cjs/public/tests/test.d.ts +9 -10
- package/build/runtime-esm/cache/cache.d.ts +20 -3
- package/build/runtime-esm/cache/cache.js +66 -7
- package/build/runtime-esm/cache/gc.js +9 -0
- package/build/runtime-esm/cache/staleManager.d.ts +30 -0
- package/build/runtime-esm/cache/staleManager.js +71 -0
- package/build/runtime-esm/cache/subscription.d.ts +2 -1
- package/build/runtime-esm/cache/subscription.js +6 -3
- package/build/runtime-esm/client/documentStore.js +1 -0
- package/build/runtime-esm/client/plugins/cache.js +5 -3
- package/build/runtime-esm/client/plugins/fetch.js +1 -0
- package/build/runtime-esm/client/plugins/query.js +1 -0
- package/build/runtime-esm/client/plugins/subscription.d.ts +1 -2
- package/build/runtime-esm/client/plugins/subscription.js +2 -0
- package/build/runtime-esm/lib/config.d.ts +4 -0
- package/build/runtime-esm/lib/index.d.ts +1 -0
- package/build/runtime-esm/lib/index.js +1 -0
- package/build/runtime-esm/lib/key.d.ts +6 -0
- package/build/runtime-esm/lib/key.js +17 -0
- package/build/runtime-esm/lib/types.d.ts +2 -2
- package/build/runtime-esm/public/cache.d.ts +8 -1
- package/build/runtime-esm/public/cache.js +3 -0
- package/build/runtime-esm/public/record.d.ts +11 -1
- package/build/runtime-esm/public/record.js +8 -1
- package/build/runtime-esm/public/tests/test.d.ts +9 -10
- package/build/test/index.d.ts +3 -3
- package/build/test-cjs/index.js +983 -828
- package/build/test-esm/index.js +983 -828
- package/build/vite-cjs/index.js +1285 -1079
- package/build/vite-esm/index.js +1285 -1079
- package/package.json +3 -2
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { computeKey } from "../lib";
|
|
2
|
+
import { computeID, defaultConfigValues, keyFieldsForType } from "../lib/config";
|
|
2
3
|
import { deepEquals } from "../lib/deepEquals";
|
|
3
4
|
import { getFieldsForType } from "../lib/selection";
|
|
4
5
|
import { GarbageCollector } from "./gc";
|
|
5
6
|
import { ListManager } from "./lists";
|
|
6
7
|
import { SchemaManager } from "./schema";
|
|
8
|
+
import { StaleManager } from "./staleManager";
|
|
7
9
|
import { InMemoryStorage } from "./storage";
|
|
8
10
|
import { evaluateKey, flattenList } from "./stuff";
|
|
9
11
|
import { InMemorySubscriptions } from "./subscription";
|
|
@@ -16,6 +18,7 @@ class Cache {
|
|
|
16
18
|
subscriptions: new InMemorySubscriptions(this),
|
|
17
19
|
lists: new ListManager(this, rootID),
|
|
18
20
|
lifetimes: new GarbageCollector(this),
|
|
21
|
+
staleManager: new StaleManager(this),
|
|
19
22
|
schema: new SchemaManager(this)
|
|
20
23
|
});
|
|
21
24
|
if (config) {
|
|
@@ -45,13 +48,14 @@ class Cache {
|
|
|
45
48
|
return subscribers;
|
|
46
49
|
}
|
|
47
50
|
read(...args) {
|
|
48
|
-
const { data, partial, hasData } = this._internal_unstable.getSelection(...args);
|
|
51
|
+
const { data, partial, stale, hasData } = this._internal_unstable.getSelection(...args);
|
|
49
52
|
if (!hasData) {
|
|
50
|
-
return { data: null, partial: false };
|
|
53
|
+
return { data: null, partial: false, stale: false };
|
|
51
54
|
}
|
|
52
55
|
return {
|
|
53
56
|
data,
|
|
54
|
-
partial
|
|
57
|
+
partial,
|
|
58
|
+
stale
|
|
55
59
|
};
|
|
56
60
|
}
|
|
57
61
|
subscribe(spec, variables = {}) {
|
|
@@ -87,6 +91,30 @@ class Cache {
|
|
|
87
91
|
setConfig(config) {
|
|
88
92
|
this._internal_unstable.setConfig(config);
|
|
89
93
|
}
|
|
94
|
+
markTypeStale(type, options = {}) {
|
|
95
|
+
if (!type) {
|
|
96
|
+
this._internal_unstable.staleManager.markAllStale();
|
|
97
|
+
} else if (!options.field) {
|
|
98
|
+
this._internal_unstable.staleManager.markTypeStale(type);
|
|
99
|
+
} else {
|
|
100
|
+
this._internal_unstable.staleManager.markTypeFieldStale(
|
|
101
|
+
type,
|
|
102
|
+
options.field,
|
|
103
|
+
options.when
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
markRecordStale(id, options) {
|
|
108
|
+
if (options.field) {
|
|
109
|
+
const key = computeKey({ field: options.field, args: options.when ?? {} });
|
|
110
|
+
this._internal_unstable.staleManager.markFieldStale(id, key);
|
|
111
|
+
} else {
|
|
112
|
+
this._internal_unstable.staleManager.markRecordStale(id);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
getFieldTime(id, field) {
|
|
116
|
+
return this._internal_unstable.staleManager.getFieldTime(id, field);
|
|
117
|
+
}
|
|
90
118
|
}
|
|
91
119
|
class CacheInternal {
|
|
92
120
|
_disabled = false;
|
|
@@ -102,6 +130,7 @@ class CacheInternal {
|
|
|
102
130
|
lists;
|
|
103
131
|
cache;
|
|
104
132
|
lifetimes;
|
|
133
|
+
staleManager;
|
|
105
134
|
schema;
|
|
106
135
|
constructor({
|
|
107
136
|
storage,
|
|
@@ -109,6 +138,7 @@ class CacheInternal {
|
|
|
109
138
|
lists,
|
|
110
139
|
cache,
|
|
111
140
|
lifetimes,
|
|
141
|
+
staleManager,
|
|
112
142
|
schema
|
|
113
143
|
}) {
|
|
114
144
|
this.storage = storage;
|
|
@@ -116,6 +146,7 @@ class CacheInternal {
|
|
|
116
146
|
this.lists = lists;
|
|
117
147
|
this.cache = cache;
|
|
118
148
|
this.lifetimes = lifetimes;
|
|
149
|
+
this.staleManager = staleManager;
|
|
119
150
|
this.schema = schema;
|
|
120
151
|
this._disabled = typeof globalThis.window === "undefined";
|
|
121
152
|
try {
|
|
@@ -136,7 +167,8 @@ class CacheInternal {
|
|
|
136
167
|
applyUpdates,
|
|
137
168
|
layer,
|
|
138
169
|
toNotify = [],
|
|
139
|
-
forceNotify
|
|
170
|
+
forceNotify,
|
|
171
|
+
forceStale
|
|
140
172
|
}) {
|
|
141
173
|
if (this._disabled) {
|
|
142
174
|
return [];
|
|
@@ -171,6 +203,11 @@ class CacheInternal {
|
|
|
171
203
|
const displayLayer = layer.isDisplayLayer(displayLayers);
|
|
172
204
|
if (displayLayer) {
|
|
173
205
|
this.lifetimes.resetLifetime(parent, key);
|
|
206
|
+
if (forceStale) {
|
|
207
|
+
this.staleManager.markFieldStale(parent, key);
|
|
208
|
+
} else {
|
|
209
|
+
this.staleManager.setFieldTimeToNow(parent, key);
|
|
210
|
+
}
|
|
174
211
|
}
|
|
175
212
|
if (!fieldSelection) {
|
|
176
213
|
let newValue = value;
|
|
@@ -402,12 +439,13 @@ class CacheInternal {
|
|
|
402
439
|
stepsFromConnection = null
|
|
403
440
|
}) {
|
|
404
441
|
if (parent === null) {
|
|
405
|
-
return { data: null, partial: false, hasData: true };
|
|
442
|
+
return { data: null, partial: false, stale: false, hasData: true };
|
|
406
443
|
}
|
|
407
444
|
const target = {};
|
|
408
445
|
let hasData = false;
|
|
409
446
|
let partial = false;
|
|
410
447
|
let cascadeNull = false;
|
|
448
|
+
let stale = false;
|
|
411
449
|
const typename = this.storage.get(parent, "__typename").value;
|
|
412
450
|
let targetSelection = getFieldsForType(selection, typename);
|
|
413
451
|
for (const [
|
|
@@ -416,6 +454,10 @@ class CacheInternal {
|
|
|
416
454
|
] of Object.entries(targetSelection)) {
|
|
417
455
|
const key = evaluateKey(keyRaw, variables);
|
|
418
456
|
const { value } = this.storage.get(parent, key);
|
|
457
|
+
const dt_field = this.staleManager.getFieldTime(parent, key);
|
|
458
|
+
if (dt_field === null) {
|
|
459
|
+
stale = true;
|
|
460
|
+
}
|
|
419
461
|
let nextStep = stepsFromConnection;
|
|
420
462
|
if (nextStep !== null) {
|
|
421
463
|
if (nextStep >= 2) {
|
|
@@ -455,6 +497,9 @@ class CacheInternal {
|
|
|
455
497
|
if (listValue.partial) {
|
|
456
498
|
partial = true;
|
|
457
499
|
}
|
|
500
|
+
if (listValue.stale) {
|
|
501
|
+
stale = true;
|
|
502
|
+
}
|
|
458
503
|
if (listValue.hasData || value.length === 0) {
|
|
459
504
|
hasData = true;
|
|
460
505
|
}
|
|
@@ -469,6 +514,9 @@ class CacheInternal {
|
|
|
469
514
|
if (objectFields.partial) {
|
|
470
515
|
partial = true;
|
|
471
516
|
}
|
|
517
|
+
if (objectFields.stale) {
|
|
518
|
+
stale = true;
|
|
519
|
+
}
|
|
472
520
|
if (objectFields.hasData) {
|
|
473
521
|
hasData = true;
|
|
474
522
|
}
|
|
@@ -480,6 +528,7 @@ class CacheInternal {
|
|
|
480
528
|
return {
|
|
481
529
|
data: cascadeNull ? null : target,
|
|
482
530
|
partial: hasData && partial,
|
|
531
|
+
stale: hasData && stale,
|
|
483
532
|
hasData
|
|
484
533
|
};
|
|
485
534
|
}
|
|
@@ -507,6 +556,7 @@ class CacheInternal {
|
|
|
507
556
|
}) {
|
|
508
557
|
const result = [];
|
|
509
558
|
let partialData = false;
|
|
559
|
+
let stale = false;
|
|
510
560
|
let hasValues = false;
|
|
511
561
|
for (const entry of linkedList) {
|
|
512
562
|
if (Array.isArray(entry)) {
|
|
@@ -526,7 +576,12 @@ class CacheInternal {
|
|
|
526
576
|
result.push(entry);
|
|
527
577
|
continue;
|
|
528
578
|
}
|
|
529
|
-
const {
|
|
579
|
+
const {
|
|
580
|
+
data,
|
|
581
|
+
partial,
|
|
582
|
+
stale: local_stale,
|
|
583
|
+
hasData
|
|
584
|
+
} = this.getSelection({
|
|
530
585
|
parent: entry,
|
|
531
586
|
selection: fields,
|
|
532
587
|
variables,
|
|
@@ -536,6 +591,9 @@ class CacheInternal {
|
|
|
536
591
|
if (partial) {
|
|
537
592
|
partialData = true;
|
|
538
593
|
}
|
|
594
|
+
if (local_stale) {
|
|
595
|
+
stale = true;
|
|
596
|
+
}
|
|
539
597
|
if (hasData) {
|
|
540
598
|
hasValues = true;
|
|
541
599
|
}
|
|
@@ -543,6 +601,7 @@ class CacheInternal {
|
|
|
543
601
|
return {
|
|
544
602
|
data: result,
|
|
545
603
|
partial: partialData,
|
|
604
|
+
stale,
|
|
546
605
|
hasData: hasValues
|
|
547
606
|
};
|
|
548
607
|
}
|
|
@@ -14,6 +14,8 @@ class GarbageCollector {
|
|
|
14
14
|
this.lifetimes.get(id).set(field, 0);
|
|
15
15
|
}
|
|
16
16
|
tick() {
|
|
17
|
+
const dt_tick = Date.now().valueOf();
|
|
18
|
+
const config_max_time = this.cache._internal_unstable.config.defaultLifetime;
|
|
17
19
|
for (const [id, fieldMap] of this.lifetimes.entries()) {
|
|
18
20
|
for (const [field, lifetime] of fieldMap.entries()) {
|
|
19
21
|
if (this.cache._internal_unstable.subscriptions.get(id, field).length > 0) {
|
|
@@ -27,6 +29,13 @@ class GarbageCollector {
|
|
|
27
29
|
if ([...fieldMap.keys()].length === 0) {
|
|
28
30
|
this.lifetimes.delete(id);
|
|
29
31
|
}
|
|
32
|
+
this.cache._internal_unstable.staleManager.delete(id, field);
|
|
33
|
+
}
|
|
34
|
+
if (config_max_time && config_max_time > 0) {
|
|
35
|
+
const dt_valueOf = this.cache.getFieldTime(id, field);
|
|
36
|
+
if (dt_valueOf && dt_tick - dt_valueOf > config_max_time) {
|
|
37
|
+
this.cache._internal_unstable.staleManager.markFieldStale(id, field);
|
|
38
|
+
}
|
|
30
39
|
}
|
|
31
40
|
}
|
|
32
41
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Cache } from './cache';
|
|
2
|
+
export declare class StaleManager {
|
|
3
|
+
#private;
|
|
4
|
+
cache: Cache;
|
|
5
|
+
private fieldsTime;
|
|
6
|
+
constructor(cache: Cache);
|
|
7
|
+
/**
|
|
8
|
+
* get the FieldTime info
|
|
9
|
+
* @param id User:1
|
|
10
|
+
* @param field firstName
|
|
11
|
+
*/
|
|
12
|
+
getFieldTime(id: string, field: string): number | undefined | null;
|
|
13
|
+
/**
|
|
14
|
+
* set the date to a field
|
|
15
|
+
* @param id User:1
|
|
16
|
+
* @param field firstName
|
|
17
|
+
*/
|
|
18
|
+
setFieldTimeToNow(id: string, field: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* set null to a field (stale)
|
|
21
|
+
* @param id User:1
|
|
22
|
+
* @param field firstName
|
|
23
|
+
*/
|
|
24
|
+
markFieldStale(id: string, field: string): void;
|
|
25
|
+
markAllStale(): void;
|
|
26
|
+
markRecordStale(id: string): void;
|
|
27
|
+
markTypeStale(type: string): void;
|
|
28
|
+
markTypeFieldStale(type: string, field: string, when?: {}): void;
|
|
29
|
+
delete(id: string, field: string): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { computeKey } from "../lib";
|
|
2
|
+
class StaleManager {
|
|
3
|
+
cache;
|
|
4
|
+
fieldsTime = /* @__PURE__ */ new Map();
|
|
5
|
+
constructor(cache) {
|
|
6
|
+
this.cache = cache;
|
|
7
|
+
}
|
|
8
|
+
#initMapId = (id) => {
|
|
9
|
+
if (!this.fieldsTime.get(id)) {
|
|
10
|
+
this.fieldsTime.set(id, /* @__PURE__ */ new Map());
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
getFieldTime(id, field) {
|
|
14
|
+
return this.fieldsTime.get(id)?.get(field);
|
|
15
|
+
}
|
|
16
|
+
setFieldTimeToNow(id, field) {
|
|
17
|
+
this.#initMapId(id);
|
|
18
|
+
this.fieldsTime.get(id)?.set(field, new Date().valueOf());
|
|
19
|
+
}
|
|
20
|
+
markFieldStale(id, field) {
|
|
21
|
+
this.#initMapId(id);
|
|
22
|
+
this.fieldsTime.get(id)?.set(field, null);
|
|
23
|
+
}
|
|
24
|
+
markAllStale() {
|
|
25
|
+
for (const [id, fieldMap] of this.fieldsTime.entries()) {
|
|
26
|
+
for (const [field] of fieldMap.entries()) {
|
|
27
|
+
this.markFieldStale(id, field);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
markRecordStale(id) {
|
|
32
|
+
const fieldsTimeOfType = this.fieldsTime.get(id);
|
|
33
|
+
if (fieldsTimeOfType) {
|
|
34
|
+
for (const [field] of fieldsTimeOfType.entries()) {
|
|
35
|
+
this.markFieldStale(id, field);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
markTypeStale(type) {
|
|
40
|
+
for (const [id, fieldMap] of this.fieldsTime.entries()) {
|
|
41
|
+
if (id.startsWith(`${type}:`)) {
|
|
42
|
+
for (const [field] of fieldMap.entries()) {
|
|
43
|
+
this.markFieldStale(id, field);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
markTypeFieldStale(type, field, when) {
|
|
49
|
+
const key = computeKey({ field, args: when });
|
|
50
|
+
for (const [id, fieldMap] of this.fieldsTime.entries()) {
|
|
51
|
+
if (id.startsWith(`${type}:`)) {
|
|
52
|
+
for (const local_field of fieldMap.keys()) {
|
|
53
|
+
if (local_field === key) {
|
|
54
|
+
this.markFieldStale(id, field);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
delete(id, field) {
|
|
61
|
+
if (this.fieldsTime.has(id)) {
|
|
62
|
+
this.fieldsTime.get(id)?.delete(field);
|
|
63
|
+
if (this.fieldsTime.get(id)?.size === 0) {
|
|
64
|
+
this.fieldsTime.delete(id);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
StaleManager
|
|
71
|
+
};
|
|
@@ -19,10 +19,11 @@ export declare class InMemorySubscriptions {
|
|
|
19
19
|
[key: string]: GraphQLValue;
|
|
20
20
|
};
|
|
21
21
|
}): void;
|
|
22
|
-
addFieldSubscription({ id, key, selection, }: {
|
|
22
|
+
addFieldSubscription({ id, key, selection, type, }: {
|
|
23
23
|
id: string;
|
|
24
24
|
key: string;
|
|
25
25
|
selection: FieldSelection;
|
|
26
|
+
type: string;
|
|
26
27
|
}): void;
|
|
27
28
|
registerList({ list, id, key, parentType, selection, filters, variables, }: {
|
|
28
29
|
list: Required<Required<SubscriptionSelection>['fields'][string]>['list'];
|
|
@@ -28,7 +28,8 @@ class InMemorySubscriptions {
|
|
|
28
28
|
this.addFieldSubscription({
|
|
29
29
|
id: parent,
|
|
30
30
|
key,
|
|
31
|
-
selection: [spec, targetSelection2]
|
|
31
|
+
selection: [spec, targetSelection2],
|
|
32
|
+
type
|
|
32
33
|
});
|
|
33
34
|
if (list) {
|
|
34
35
|
this.registerList({
|
|
@@ -65,7 +66,8 @@ class InMemorySubscriptions {
|
|
|
65
66
|
addFieldSubscription({
|
|
66
67
|
id,
|
|
67
68
|
key,
|
|
68
|
-
selection
|
|
69
|
+
selection,
|
|
70
|
+
type
|
|
69
71
|
}) {
|
|
70
72
|
const spec = selection[0];
|
|
71
73
|
if (!this.subscribers[id]) {
|
|
@@ -137,7 +139,8 @@ class InMemorySubscriptions {
|
|
|
137
139
|
this.addFieldSubscription({
|
|
138
140
|
id: parent,
|
|
139
141
|
key,
|
|
140
|
-
selection: [spec, fieldSelection]
|
|
142
|
+
selection: [spec, fieldSelection],
|
|
143
|
+
type: linkedType
|
|
141
144
|
});
|
|
142
145
|
if (list) {
|
|
143
146
|
this.registerList({
|
|
@@ -23,7 +23,8 @@ const cachePolicyPlugin = ({
|
|
|
23
23
|
data: value.data,
|
|
24
24
|
errors: null,
|
|
25
25
|
source: DataSource.Cache,
|
|
26
|
-
partial: value.partial
|
|
26
|
+
partial: value.partial,
|
|
27
|
+
stale: value.stale
|
|
27
28
|
});
|
|
28
29
|
}
|
|
29
30
|
useCache = !!(value.data !== null && allowed);
|
|
@@ -34,10 +35,11 @@ const cachePolicyPlugin = ({
|
|
|
34
35
|
data: value.data,
|
|
35
36
|
errors: null,
|
|
36
37
|
source: DataSource.Cache,
|
|
37
|
-
partial: value.partial
|
|
38
|
+
partial: value.partial,
|
|
39
|
+
stale: value.stale
|
|
38
40
|
});
|
|
39
41
|
}
|
|
40
|
-
if (useCache && !value.partial) {
|
|
42
|
+
if (useCache && !value.partial && !value.stale) {
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
45
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { GraphQLObject } from '../../lib/types';
|
|
2
1
|
import type { ClientPluginContext } from '../documentStore';
|
|
3
2
|
export declare function subscriptionPlugin(factory: SubscriptionHandler): import("../documentStore").ClientPlugin;
|
|
4
3
|
export type SubscriptionHandler = (ctx: ClientPluginContext) => {
|
|
@@ -7,7 +6,7 @@ export type SubscriptionHandler = (ctx: ClientPluginContext) => {
|
|
|
7
6
|
variables?: {};
|
|
8
7
|
}, handlers: {
|
|
9
8
|
next: (payload: {
|
|
10
|
-
data?:
|
|
9
|
+
data?: {} | null;
|
|
11
10
|
errors?: readonly {
|
|
12
11
|
message: string;
|
|
13
12
|
}[];
|
|
@@ -43,6 +43,7 @@ function subscriptionPlugin(factory) {
|
|
|
43
43
|
errors: [...errors ?? []],
|
|
44
44
|
fetching: false,
|
|
45
45
|
partial: true,
|
|
46
|
+
stale: false,
|
|
46
47
|
source: DataSource.Network,
|
|
47
48
|
variables: ctx.variables ?? null
|
|
48
49
|
});
|
|
@@ -51,6 +52,7 @@ function subscriptionPlugin(factory) {
|
|
|
51
52
|
clearSubscription?.();
|
|
52
53
|
resolve(ctx, {
|
|
53
54
|
partial: true,
|
|
55
|
+
stale: false,
|
|
54
56
|
source: DataSource.Network,
|
|
55
57
|
data: null,
|
|
56
58
|
errors: [data],
|
|
@@ -55,6 +55,10 @@ export type ConfigFile = {
|
|
|
55
55
|
* Specifies whether or not the cache should always use partial data. For more information: https://www.houdinigraphql.com/guides/caching-data#partial-data
|
|
56
56
|
*/
|
|
57
57
|
defaultPartial?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Specifies after how long a data goes stale in miliseconds. (default: `undefined`)
|
|
60
|
+
*/
|
|
61
|
+
defaultLifetime?: number;
|
|
58
62
|
/**
|
|
59
63
|
* Specifies whether mutations should append or prepend list. For more information: https://www.houdinigraphql.com/api/graphql (default: `append`)
|
|
60
64
|
*/
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const computeKey = ({ field, args }) => {
|
|
2
|
+
const keys = Object.keys(args ?? {});
|
|
3
|
+
keys.sort();
|
|
4
|
+
return args && keys.length > 0 ? `${field}(${keys.map((key) => `${key}: ${stringifyObjectWithNoQuotesOnKeys(args[key])}`).join(", ")})` : field;
|
|
5
|
+
};
|
|
6
|
+
const stringifyObjectWithNoQuotesOnKeys = (obj_from_json) => {
|
|
7
|
+
if (Array.isArray(obj_from_json)) {
|
|
8
|
+
return `[${obj_from_json.map((obj) => `${stringifyObjectWithNoQuotesOnKeys(obj)}`).join(", ")}]`;
|
|
9
|
+
}
|
|
10
|
+
if (typeof obj_from_json !== "object" || obj_from_json instanceof Date || obj_from_json === null) {
|
|
11
|
+
return JSON.stringify(obj_from_json).replace(/"([^"]+)":/g, "$1: ");
|
|
12
|
+
}
|
|
13
|
+
return `{${Object.keys(obj_from_json).map((key) => `${key}: ${stringifyObjectWithNoQuotesOnKeys(obj_from_json[key])}`).join(", ")}}`;
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
computeKey
|
|
17
|
+
};
|
|
@@ -80,7 +80,7 @@ export type BaseCompiledDocument = {
|
|
|
80
80
|
paginated: boolean;
|
|
81
81
|
direction: 'forward' | 'backward' | 'both';
|
|
82
82
|
};
|
|
83
|
-
|
|
83
|
+
plugin_data?: Record<string, any>;
|
|
84
84
|
};
|
|
85
85
|
export type HoudiniFetchContext = {
|
|
86
86
|
variables: () => {};
|
|
@@ -164,7 +164,6 @@ export type SubscriptionSpec = {
|
|
|
164
164
|
export type FetchQueryResult<_Data> = {
|
|
165
165
|
result: RequestPayload<_Data | null>;
|
|
166
166
|
source: DataSource | null;
|
|
167
|
-
partial: boolean;
|
|
168
167
|
};
|
|
169
168
|
export type QueryResult<_Data = GraphQLObject, _Input = Record<string, any>> = {
|
|
170
169
|
data: _Data | null;
|
|
@@ -173,6 +172,7 @@ export type QueryResult<_Data = GraphQLObject, _Input = Record<string, any>> = {
|
|
|
173
172
|
}[] | null;
|
|
174
173
|
fetching: boolean;
|
|
175
174
|
partial: boolean;
|
|
175
|
+
stale: boolean;
|
|
176
176
|
source: DataSource | null;
|
|
177
177
|
variables: _Input | null;
|
|
178
178
|
};
|
|
@@ -2,7 +2,7 @@ import type { Cache as _Cache } from '../cache/cache';
|
|
|
2
2
|
import { type QueryArtifact } from '../lib';
|
|
3
3
|
import { ListCollection } from './list';
|
|
4
4
|
import { Record } from './record';
|
|
5
|
-
import type { CacheTypeDef, IDFields, QueryInput, QueryList, QueryValue, TypeNames, ValidLists } from './types';
|
|
5
|
+
import type { ArgType, CacheTypeDef, IDFields, QueryInput, QueryList, QueryValue, TypeFieldNames, TypeNames, ValidLists } from './types';
|
|
6
6
|
export declare class Cache<Def extends CacheTypeDef> {
|
|
7
7
|
_internal_unstable: _Cache;
|
|
8
8
|
constructor(cache: _Cache);
|
|
@@ -29,4 +29,11 @@ export declare class Cache<Def extends CacheTypeDef> {
|
|
|
29
29
|
data: QueryValue<QueryList<Def>, _Query>;
|
|
30
30
|
variables?: QueryInput<QueryList<Def>, _Query>;
|
|
31
31
|
}): void;
|
|
32
|
+
/**
|
|
33
|
+
* Mark some elements of the cache stale.
|
|
34
|
+
*/
|
|
35
|
+
markStale<_Type extends TypeNames<Def>, _Field extends TypeFieldNames<Def, _Type>>(type?: _Type, options?: {
|
|
36
|
+
field?: _Field;
|
|
37
|
+
when?: ArgType<Def, _Type, _Field>;
|
|
38
|
+
}): void;
|
|
32
39
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FragmentArtifact } from '../lib/types';
|
|
2
2
|
import type { Cache } from './cache';
|
|
3
|
-
import type { CacheTypeDef, FragmentList, FragmentValue, FragmentVariables, ValidTypes } from './types';
|
|
3
|
+
import type { ArgType, CacheTypeDef, FragmentList, FragmentValue, FragmentVariables, TypeFieldNames, ValidTypes } from './types';
|
|
4
4
|
export declare class Record<Def extends CacheTypeDef, Type extends ValidTypes<Def>> {
|
|
5
5
|
#private;
|
|
6
6
|
type: string;
|
|
@@ -26,6 +26,16 @@ export declare class Record<Def extends CacheTypeDef, Type extends ValidTypes<De
|
|
|
26
26
|
fragment: _Fragment;
|
|
27
27
|
data: FragmentValue<FragmentList<Def, Type>, _Fragment>;
|
|
28
28
|
variables?: FragmentVariables<FragmentList<Def, Type>, _Fragment>;
|
|
29
|
+
forceStale?: boolean;
|
|
29
30
|
}): void;
|
|
30
31
|
delete(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Mark some elements of the record stale in the cache.
|
|
34
|
+
* @param field
|
|
35
|
+
* @param when
|
|
36
|
+
*/
|
|
37
|
+
markStale<Field extends TypeFieldNames<Def, Type>>({ field, when, }?: {
|
|
38
|
+
field?: Field;
|
|
39
|
+
when?: ArgType<Def, Type, Field>;
|
|
40
|
+
}): void;
|
|
31
41
|
}
|
|
@@ -47,12 +47,19 @@ class Record {
|
|
|
47
47
|
config: this.#cache.config,
|
|
48
48
|
artifact: args.fragment.artifact,
|
|
49
49
|
input: args.variables
|
|
50
|
-
}) ?? void 0
|
|
50
|
+
}) ?? void 0,
|
|
51
|
+
forceStale: args.forceStale
|
|
51
52
|
});
|
|
52
53
|
}
|
|
53
54
|
delete() {
|
|
54
55
|
this.#cache._internal_unstable.delete(this.#id);
|
|
55
56
|
}
|
|
57
|
+
markStale({
|
|
58
|
+
field,
|
|
59
|
+
when
|
|
60
|
+
} = {}) {
|
|
61
|
+
this.#cache._internal_unstable.markRecordStale(this.#id, { field, when });
|
|
62
|
+
}
|
|
56
63
|
}
|
|
57
64
|
export {
|
|
58
65
|
Record
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type SubscriptionSelection, type FragmentArtifact, type QueryArtifact } from '../../lib';
|
|
2
2
|
import { Cache } from '../cache';
|
|
3
3
|
import type { Record } from '../record';
|
|
4
|
-
type
|
|
4
|
+
export type CacheTypeDefTest = {
|
|
5
5
|
types: {
|
|
6
6
|
__ROOT__: {
|
|
7
7
|
idFields: {};
|
|
@@ -16,23 +16,23 @@ type CacheTypeDef = {
|
|
|
16
16
|
args: never;
|
|
17
17
|
};
|
|
18
18
|
viewer: {
|
|
19
|
-
type: Record<
|
|
19
|
+
type: Record<CacheTypeDefTest, 'User'> | null;
|
|
20
20
|
args: never;
|
|
21
21
|
};
|
|
22
22
|
pets: {
|
|
23
|
-
type: (Record<
|
|
23
|
+
type: (Record<CacheTypeDefTest, 'Cat'> | Record<CacheTypeDefTest, 'User'>)[];
|
|
24
24
|
args: never;
|
|
25
25
|
};
|
|
26
26
|
listOfLists: {
|
|
27
|
-
type: ((Record<
|
|
27
|
+
type: ((Record<CacheTypeDefTest, 'Cat'> | Record<CacheTypeDefTest, 'User'> | null | (null | Record<CacheTypeDefTest, 'User'>)[])[] | Record<CacheTypeDefTest, 'Cat'> | Record<CacheTypeDefTest, 'User'> | null)[];
|
|
28
28
|
args: never;
|
|
29
29
|
};
|
|
30
30
|
users: {
|
|
31
|
-
type: Record<
|
|
31
|
+
type: Record<CacheTypeDefTest, 'User'>[] | null;
|
|
32
32
|
args: never;
|
|
33
33
|
};
|
|
34
34
|
pet: {
|
|
35
|
-
type: Record<
|
|
35
|
+
type: Record<CacheTypeDefTest, 'Cat'> | Record<CacheTypeDefTest, 'User'>;
|
|
36
36
|
args: never;
|
|
37
37
|
};
|
|
38
38
|
};
|
|
@@ -60,7 +60,7 @@ type CacheTypeDef = {
|
|
|
60
60
|
args: never;
|
|
61
61
|
};
|
|
62
62
|
parent: {
|
|
63
|
-
type: Record<
|
|
63
|
+
type: Record<CacheTypeDefTest, 'User'>;
|
|
64
64
|
args: never;
|
|
65
65
|
};
|
|
66
66
|
id: {
|
|
@@ -84,7 +84,7 @@ type CacheTypeDef = {
|
|
|
84
84
|
args: never;
|
|
85
85
|
};
|
|
86
86
|
parent: {
|
|
87
|
-
type: Record<
|
|
87
|
+
type: Record<CacheTypeDefTest, 'User'> | null;
|
|
88
88
|
args: never;
|
|
89
89
|
};
|
|
90
90
|
id: {
|
|
@@ -147,11 +147,10 @@ type CacheTypeDef = {
|
|
|
147
147
|
};
|
|
148
148
|
};
|
|
149
149
|
};
|
|
150
|
-
export declare const testCache: () => Cache<
|
|
150
|
+
export declare const testCache: () => Cache<CacheTypeDefTest>;
|
|
151
151
|
export declare const testFragment: (selection: SubscriptionSelection) => {
|
|
152
152
|
artifact: FragmentArtifact;
|
|
153
153
|
};
|
|
154
154
|
export declare const testQuery: (selection: SubscriptionSelection) => {
|
|
155
155
|
artifact: QueryArtifact;
|
|
156
156
|
};
|
|
157
|
-
export {};
|