houdini 0.17.9 → 0.17.10
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/README.md +33 -0
- package/build/cmd-cjs/index.js +2 -2
- package/build/cmd-esm/index.js +2 -2
- package/package.json +16 -1
- package/.turbo/turbo-compile.log +0 -5
- package/.turbo/turbo-typedefs.log +0 -5
- package/CHANGELOG.md +0 -377
- package/src/cmd/generate.ts +0 -54
- package/src/cmd/index.ts +0 -60
- package/src/cmd/init.ts +0 -637
- package/src/cmd/pullSchema.ts +0 -40
- package/src/codegen/generators/artifacts/artifacts.test.ts +0 -3246
- package/src/codegen/generators/artifacts/fieldKey.ts +0 -60
- package/src/codegen/generators/artifacts/index.ts +0 -330
- package/src/codegen/generators/artifacts/indexFile.ts +0 -24
- package/src/codegen/generators/artifacts/inputs.ts +0 -81
- package/src/codegen/generators/artifacts/operations.ts +0 -281
- package/src/codegen/generators/artifacts/pagination.test.ts +0 -664
- package/src/codegen/generators/artifacts/policy.test.ts +0 -298
- package/src/codegen/generators/artifacts/selection.ts +0 -208
- package/src/codegen/generators/artifacts/utils.test.ts +0 -118
- package/src/codegen/generators/artifacts/utils.ts +0 -108
- package/src/codegen/generators/definitions/enums.test.ts +0 -61
- package/src/codegen/generators/definitions/enums.ts +0 -68
- package/src/codegen/generators/definitions/index.ts +0 -11
- package/src/codegen/generators/definitions/schema.test.ts +0 -236
- package/src/codegen/generators/index.ts +0 -6
- package/src/codegen/generators/indexFile/index.ts +0 -63
- package/src/codegen/generators/indexFile/indexFile.test.ts +0 -72
- package/src/codegen/generators/persistedQueries/index.ts +0 -55
- package/src/codegen/generators/persistedQueries/persistedQuery.test.ts +0 -26
- package/src/codegen/generators/runtime/index.test.ts +0 -74
- package/src/codegen/generators/runtime/index.ts +0 -64
- package/src/codegen/generators/runtime/runtime.test.ts +0 -25
- package/src/codegen/generators/typescript/addReferencedInputTypes.ts +0 -77
- package/src/codegen/generators/typescript/index.ts +0 -412
- package/src/codegen/generators/typescript/inlineType.ts +0 -409
- package/src/codegen/generators/typescript/typeReference.ts +0 -44
- package/src/codegen/generators/typescript/types.ts +0 -81
- package/src/codegen/generators/typescript/typescript.test.ts +0 -1434
- package/src/codegen/index.ts +0 -406
- package/src/codegen/transforms/addID.test.ts +0 -93
- package/src/codegen/transforms/addID.ts +0 -86
- package/src/codegen/transforms/composeQueries.test.ts +0 -50
- package/src/codegen/transforms/composeQueries.ts +0 -154
- package/src/codegen/transforms/fragmentVariables.test.ts +0 -636
- package/src/codegen/transforms/fragmentVariables.ts +0 -417
- package/src/codegen/transforms/index.ts +0 -7
- package/src/codegen/transforms/list.ts +0 -484
- package/src/codegen/transforms/lists.test.ts +0 -530
- package/src/codegen/transforms/paginate.test.ts +0 -1528
- package/src/codegen/transforms/paginate.ts +0 -770
- package/src/codegen/transforms/schema.test.ts +0 -136
- package/src/codegen/transforms/schema.ts +0 -109
- package/src/codegen/transforms/typename.test.ts +0 -125
- package/src/codegen/transforms/typename.ts +0 -55
- package/src/codegen/utils/commonjs.ts +0 -26
- package/src/codegen/utils/flattenSelections.ts +0 -179
- package/src/codegen/utils/graphql.test.ts +0 -35
- package/src/codegen/utils/graphql.ts +0 -79
- package/src/codegen/utils/index.ts +0 -5
- package/src/codegen/utils/moduleExport.ts +0 -27
- package/src/codegen/utils/murmur.ts +0 -79
- package/src/codegen/validators/index.ts +0 -4
- package/src/codegen/validators/noIDAlias.test.ts +0 -71
- package/src/codegen/validators/noIDAlias.ts +0 -39
- package/src/codegen/validators/plugins.ts +0 -25
- package/src/codegen/validators/typeCheck.test.ts +0 -960
- package/src/codegen/validators/typeCheck.ts +0 -1086
- package/src/codegen/validators/uniqueNames.test.ts +0 -59
- package/src/codegen/validators/uniqueNames.ts +0 -39
- package/src/lib/cleanupFiles.ts +0 -20
- package/src/lib/config.test.ts +0 -13
- package/src/lib/config.ts +0 -954
- package/src/lib/constants.ts +0 -11
- package/src/lib/error.ts +0 -24
- package/src/lib/fs.ts +0 -285
- package/src/lib/graphql.test.ts +0 -211
- package/src/lib/graphql.ts +0 -200
- package/src/lib/imports.ts +0 -82
- package/src/lib/index.ts +0 -17
- package/src/lib/introspection.ts +0 -39
- package/src/lib/parse.test.ts +0 -75
- package/src/lib/parse.ts +0 -23
- package/src/lib/path.ts +0 -49
- package/src/lib/pipeline.ts +0 -17
- package/src/lib/types.ts +0 -34
- package/src/lib/walk.ts +0 -104
- package/src/runtime/cache/cache.ts +0 -1026
- package/src/runtime/cache/gc.ts +0 -56
- package/src/runtime/cache/index.ts +0 -3
- package/src/runtime/cache/lists.ts +0 -516
- package/src/runtime/cache/storage.ts +0 -574
- package/src/runtime/cache/stuff.ts +0 -77
- package/src/runtime/cache/subscription.ts +0 -329
- package/src/runtime/cache/tests/availability.test.ts +0 -408
- package/src/runtime/cache/tests/gc.test.ts +0 -319
- package/src/runtime/cache/tests/keys.test.ts +0 -36
- package/src/runtime/cache/tests/list.test.ts +0 -3854
- package/src/runtime/cache/tests/readwrite.test.ts +0 -1201
- package/src/runtime/cache/tests/scalars.test.ts +0 -218
- package/src/runtime/cache/tests/storage.test.ts +0 -426
- package/src/runtime/cache/tests/subscriptions.test.ts +0 -1757
- package/src/runtime/index.ts +0 -29
- package/src/runtime/lib/config.ts +0 -211
- package/src/runtime/lib/constants.ts +0 -17
- package/src/runtime/lib/deepEquals.ts +0 -32
- package/src/runtime/lib/errors.ts +0 -8
- package/src/runtime/lib/index.ts +0 -8
- package/src/runtime/lib/log.ts +0 -69
- package/src/runtime/lib/network.ts +0 -303
- package/src/runtime/lib/networkUtils.ts +0 -151
- package/src/runtime/lib/scalars.test.ts +0 -877
- package/src/runtime/lib/scalars.ts +0 -195
- package/src/runtime/lib/types.ts +0 -195
- package/src/test/index.ts +0 -294
- package/src/vite/ast.ts +0 -107
- package/src/vite/houdini.ts +0 -113
- package/src/vite/imports.ts +0 -129
- package/src/vite/index.ts +0 -55
- package/src/vite/schema.ts +0 -80
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import type { SubscriptionSpec, SubscriptionSelection, GraphQLObject } from '../lib/types'
|
|
2
|
-
import type { GraphQLValue } from '../lib/types'
|
|
3
|
-
import { Cache, LinkedList } from './cache'
|
|
4
|
-
import { evaluateKey, flattenList } from './stuff'
|
|
5
|
-
|
|
6
|
-
// manage the subscriptions
|
|
7
|
-
export class InMemorySubscriptions {
|
|
8
|
-
private cache: Cache
|
|
9
|
-
|
|
10
|
-
constructor(cache: Cache) {
|
|
11
|
-
this.cache = cache
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
private subscribers: { [id: string]: { [fieldName: string]: SubscriptionSpec[] } } = {}
|
|
15
|
-
private referenceCounts: {
|
|
16
|
-
[id: string]: { [fieldName: string]: Map<SubscriptionSpec['set'], number> }
|
|
17
|
-
} = {}
|
|
18
|
-
private keyVersions: { [key: string]: Set<string> } = {}
|
|
19
|
-
|
|
20
|
-
add({
|
|
21
|
-
parent,
|
|
22
|
-
spec,
|
|
23
|
-
selection,
|
|
24
|
-
variables,
|
|
25
|
-
parentType,
|
|
26
|
-
}: {
|
|
27
|
-
parent: string
|
|
28
|
-
parentType?: string
|
|
29
|
-
spec: SubscriptionSpec
|
|
30
|
-
selection: SubscriptionSelection
|
|
31
|
-
variables: { [key: string]: GraphQLValue }
|
|
32
|
-
}) {
|
|
33
|
-
for (const fieldSelection of Object.values(selection)) {
|
|
34
|
-
const { keyRaw, fields, type } = fieldSelection
|
|
35
|
-
|
|
36
|
-
const key = evaluateKey(keyRaw, variables)
|
|
37
|
-
|
|
38
|
-
// add the subscriber to the field
|
|
39
|
-
this.addFieldSubscription({
|
|
40
|
-
id: parent,
|
|
41
|
-
key,
|
|
42
|
-
selection: fieldSelection,
|
|
43
|
-
spec,
|
|
44
|
-
parentType: parentType || spec.rootType,
|
|
45
|
-
variables,
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
// if the field points to a link, we need to subscribe to any fields of that
|
|
49
|
-
// linked record
|
|
50
|
-
if (fields) {
|
|
51
|
-
// if the link points to a record then we just have to add it to the one
|
|
52
|
-
const { value: linkedRecord } = this.cache._internal_unstable.storage.get(
|
|
53
|
-
parent,
|
|
54
|
-
key
|
|
55
|
-
)
|
|
56
|
-
let children = !Array.isArray(linkedRecord)
|
|
57
|
-
? [linkedRecord]
|
|
58
|
-
: flattenList(linkedRecord) || []
|
|
59
|
-
|
|
60
|
-
// add the subscriber to every child
|
|
61
|
-
for (const child of children) {
|
|
62
|
-
// avoid null children
|
|
63
|
-
if (!child) {
|
|
64
|
-
continue
|
|
65
|
-
}
|
|
66
|
-
// make sure the children update this subscription
|
|
67
|
-
this.add({
|
|
68
|
-
parent: child as string,
|
|
69
|
-
spec,
|
|
70
|
-
selection: fields,
|
|
71
|
-
variables,
|
|
72
|
-
parentType: type,
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
addFieldSubscription({
|
|
80
|
-
id,
|
|
81
|
-
key,
|
|
82
|
-
selection,
|
|
83
|
-
spec,
|
|
84
|
-
parentType,
|
|
85
|
-
variables,
|
|
86
|
-
}: {
|
|
87
|
-
id: string
|
|
88
|
-
key: string
|
|
89
|
-
selection: SubscriptionSelection[string]
|
|
90
|
-
spec: SubscriptionSpec
|
|
91
|
-
parentType: string
|
|
92
|
-
variables: GraphQLObject
|
|
93
|
-
}) {
|
|
94
|
-
// if we haven't seen the id or field before, create a list we can add to
|
|
95
|
-
if (!this.subscribers[id]) {
|
|
96
|
-
this.subscribers[id] = {}
|
|
97
|
-
}
|
|
98
|
-
if (!this.subscribers[id][key]) {
|
|
99
|
-
this.subscribers[id][key] = []
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// if this is the first time we've seen the raw key
|
|
103
|
-
if (!this.keyVersions[key]) {
|
|
104
|
-
this.keyVersions[key] = new Set()
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// add this version of the key if we need to
|
|
108
|
-
this.keyVersions[key].add(key)
|
|
109
|
-
|
|
110
|
-
if (!this.subscribers[id][key].map(({ set }) => set).includes(spec.set)) {
|
|
111
|
-
this.subscribers[id][key].push(spec)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// if this is the first time we've seen this key
|
|
115
|
-
if (!this.referenceCounts[id]) {
|
|
116
|
-
this.referenceCounts[id] = {}
|
|
117
|
-
}
|
|
118
|
-
if (!this.referenceCounts[id][key]) {
|
|
119
|
-
this.referenceCounts[id][key] = new Map()
|
|
120
|
-
}
|
|
121
|
-
const counts = this.referenceCounts[id][key]
|
|
122
|
-
|
|
123
|
-
// we're going to increment the current value by one
|
|
124
|
-
counts.set(spec.set, (counts.get(spec.set) || 0) + 1)
|
|
125
|
-
|
|
126
|
-
// reset the lifetime for the key
|
|
127
|
-
this.cache._internal_unstable.lifetimes.resetLifetime(id, key)
|
|
128
|
-
|
|
129
|
-
// if this field is marked as a list, register it. this will overwrite existing list handlers
|
|
130
|
-
// so that they can get up to date filters
|
|
131
|
-
const { fields, list, filters } = selection
|
|
132
|
-
if (fields && list) {
|
|
133
|
-
this.cache._internal_unstable.lists.add({
|
|
134
|
-
name: list.name,
|
|
135
|
-
connection: list.connection,
|
|
136
|
-
recordID: id,
|
|
137
|
-
recordType:
|
|
138
|
-
(this.cache._internal_unstable.storage.get(id, '__typename')
|
|
139
|
-
?.value as string) || parentType,
|
|
140
|
-
listType: list.type,
|
|
141
|
-
key,
|
|
142
|
-
selection: fields,
|
|
143
|
-
filters: Object.entries(filters || {}).reduce((acc, [key, { kind, value }]) => {
|
|
144
|
-
return {
|
|
145
|
-
...acc,
|
|
146
|
-
[key]: kind !== 'Variable' ? value : variables[value as string],
|
|
147
|
-
}
|
|
148
|
-
}, {}),
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// this is different from add because of the treatment of lists
|
|
154
|
-
addMany({
|
|
155
|
-
parent,
|
|
156
|
-
selection,
|
|
157
|
-
variables,
|
|
158
|
-
subscribers,
|
|
159
|
-
parentType,
|
|
160
|
-
}: {
|
|
161
|
-
parent: string
|
|
162
|
-
selection: SubscriptionSelection
|
|
163
|
-
variables: {}
|
|
164
|
-
subscribers: SubscriptionSpec[]
|
|
165
|
-
parentType: string
|
|
166
|
-
}) {
|
|
167
|
-
// look at every field in the selection and add the subscribers
|
|
168
|
-
for (const fieldSelection of Object.values(selection)) {
|
|
169
|
-
const { type: linkedType, keyRaw, fields } = fieldSelection
|
|
170
|
-
const key = evaluateKey(keyRaw, variables)
|
|
171
|
-
|
|
172
|
-
// add the subscriber to the
|
|
173
|
-
for (const spec of subscribers) {
|
|
174
|
-
this.addFieldSubscription({
|
|
175
|
-
id: parent,
|
|
176
|
-
key,
|
|
177
|
-
selection: fieldSelection,
|
|
178
|
-
spec,
|
|
179
|
-
parentType,
|
|
180
|
-
variables,
|
|
181
|
-
})
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// if there are fields under this
|
|
185
|
-
if (fields) {
|
|
186
|
-
const { value: link } = this.cache._internal_unstable.storage.get(parent, key)
|
|
187
|
-
|
|
188
|
-
// figure out who else needs subscribers
|
|
189
|
-
const children = !Array.isArray(link)
|
|
190
|
-
? ([link] as string[])
|
|
191
|
-
: flattenList(link as string[])
|
|
192
|
-
for (const linkedRecord of children) {
|
|
193
|
-
// avoid null records
|
|
194
|
-
if (!linkedRecord) {
|
|
195
|
-
continue
|
|
196
|
-
}
|
|
197
|
-
// insert the subscriber
|
|
198
|
-
this.addMany({
|
|
199
|
-
parent: linkedRecord,
|
|
200
|
-
selection: fields,
|
|
201
|
-
variables,
|
|
202
|
-
subscribers,
|
|
203
|
-
parentType: linkedType,
|
|
204
|
-
})
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
get(id: string, field: string): SubscriptionSpec[] {
|
|
211
|
-
return this.subscribers[id]?.[field] || []
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
remove(
|
|
215
|
-
id: string,
|
|
216
|
-
fields: SubscriptionSelection,
|
|
217
|
-
targets: SubscriptionSpec[],
|
|
218
|
-
variables: {},
|
|
219
|
-
visited: string[] = []
|
|
220
|
-
) {
|
|
221
|
-
visited.push(id)
|
|
222
|
-
|
|
223
|
-
// walk down to every record we know about
|
|
224
|
-
const linkedIDs: [string, SubscriptionSelection][] = []
|
|
225
|
-
|
|
226
|
-
// look at the fields for ones corresponding to links
|
|
227
|
-
for (const selection of Object.values(fields)) {
|
|
228
|
-
const key = evaluateKey(selection.keyRaw, variables)
|
|
229
|
-
|
|
230
|
-
// remove the subscribers for the field
|
|
231
|
-
this.removeSubscribers(id, key, targets)
|
|
232
|
-
|
|
233
|
-
// if there is no subselection it doesn't point to a link, move on
|
|
234
|
-
if (!selection.fields) {
|
|
235
|
-
continue
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// if there is a link associated with this field we need to destroy the handler
|
|
239
|
-
if (selection.list) {
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const { value: previousValue } = this.cache._internal_unstable.storage.get(id, key)
|
|
243
|
-
|
|
244
|
-
// if its not a list, wrap it as one so we can dry things up
|
|
245
|
-
const links = !Array.isArray(previousValue)
|
|
246
|
-
? [previousValue as string]
|
|
247
|
-
: flattenList(previousValue as LinkedList)
|
|
248
|
-
|
|
249
|
-
for (const link of links) {
|
|
250
|
-
if (link !== null) {
|
|
251
|
-
linkedIDs.push([link, selection.fields])
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
for (const [linkedRecordID, linkFields] of linkedIDs) {
|
|
257
|
-
this.remove(linkedRecordID, linkFields, targets, visited)
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
private removeSubscribers(id: string, fieldName: string, specs: SubscriptionSpec[]) {
|
|
262
|
-
// build up a list of the sets we actually need to remove after
|
|
263
|
-
// checking reference counts
|
|
264
|
-
let targets: SubscriptionSpec['set'][] = []
|
|
265
|
-
|
|
266
|
-
for (const spec of specs) {
|
|
267
|
-
// if we dont know this field/set combo, there's nothing to do (probably a bug somewhere)
|
|
268
|
-
if (!this.referenceCounts[id]?.[fieldName]?.has(spec.set)) {
|
|
269
|
-
continue
|
|
270
|
-
}
|
|
271
|
-
const counts = this.referenceCounts[id][fieldName]
|
|
272
|
-
const newVal = (counts.get(spec.set) || 0) - 1
|
|
273
|
-
|
|
274
|
-
// decrement the reference of every field
|
|
275
|
-
counts.set(spec.set, newVal)
|
|
276
|
-
|
|
277
|
-
// if that was the last reference we knew of
|
|
278
|
-
if (newVal <= 0) {
|
|
279
|
-
targets.push(spec.set)
|
|
280
|
-
// remove the reference to the set function
|
|
281
|
-
counts.delete(spec.set)
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// we do need to remove the set from the list
|
|
286
|
-
if (this.subscribers[id]) {
|
|
287
|
-
this.subscribers[id][fieldName] = this.get(id, fieldName).filter(
|
|
288
|
-
({ set }) => !targets.includes(set)
|
|
289
|
-
)
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
removeAllSubscribers(id: string, targets?: SubscriptionSpec[], visited: string[] = []) {
|
|
294
|
-
visited.push(id)
|
|
295
|
-
|
|
296
|
-
// every field that currently being subscribed to needs to be cleaned up
|
|
297
|
-
for (const field of Object.keys(this.subscribers[id] || [])) {
|
|
298
|
-
// grab the current set of subscribers
|
|
299
|
-
const subscribers = targets || this.subscribers[id][field]
|
|
300
|
-
|
|
301
|
-
// delete the subscriber for the field
|
|
302
|
-
this.removeSubscribers(id, field, subscribers)
|
|
303
|
-
|
|
304
|
-
// look up the value for the field so we can remove any subscribers that existed because of a
|
|
305
|
-
// subscriber to this record
|
|
306
|
-
const { value, kind } = this.cache._internal_unstable.storage.get(id, field)
|
|
307
|
-
|
|
308
|
-
// if the field is a scalar, there's nothing more to do
|
|
309
|
-
if (kind === 'scalar') {
|
|
310
|
-
continue
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// if the value is a single link , wrap it in a list. otherwise, flatten the link list
|
|
314
|
-
const nextTargets = Array.isArray(value)
|
|
315
|
-
? flattenList(value as LinkedList)
|
|
316
|
-
: [value as string]
|
|
317
|
-
|
|
318
|
-
for (const id of nextTargets) {
|
|
319
|
-
// if we have already visited this id, move on
|
|
320
|
-
if (visited.includes(id)) {
|
|
321
|
-
continue
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// keep walking down
|
|
325
|
-
this.removeAllSubscribers(id, subscribers, visited)
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
@@ -1,408 +0,0 @@
|
|
|
1
|
-
import { test, expect, vi } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { testConfigFile } from '../../../test'
|
|
4
|
-
import { Cache } from '../cache'
|
|
5
|
-
|
|
6
|
-
const config = testConfigFile()
|
|
7
|
-
|
|
8
|
-
test('not partial', function () {
|
|
9
|
-
// instantiate the cache
|
|
10
|
-
const cache = new Cache(config)
|
|
11
|
-
|
|
12
|
-
const selection = {
|
|
13
|
-
viewer: {
|
|
14
|
-
type: 'User',
|
|
15
|
-
keyRaw: 'viewer',
|
|
16
|
-
fields: {
|
|
17
|
-
id: {
|
|
18
|
-
type: 'ID',
|
|
19
|
-
keyRaw: 'id',
|
|
20
|
-
},
|
|
21
|
-
firstName: {
|
|
22
|
-
type: 'String',
|
|
23
|
-
keyRaw: 'firstName',
|
|
24
|
-
},
|
|
25
|
-
friends: {
|
|
26
|
-
type: 'User',
|
|
27
|
-
keyRaw: 'friends',
|
|
28
|
-
nullable: true,
|
|
29
|
-
fields: {
|
|
30
|
-
id: {
|
|
31
|
-
type: 'ID',
|
|
32
|
-
keyRaw: 'id',
|
|
33
|
-
},
|
|
34
|
-
firstName: {
|
|
35
|
-
type: 'String',
|
|
36
|
-
keyRaw: 'firstName',
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// make sure we can't resolve it already
|
|
45
|
-
expect(cache.read({ selection })).toMatchObject({
|
|
46
|
-
data: null,
|
|
47
|
-
partial: false,
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
// add some data to the cache
|
|
51
|
-
cache.write({
|
|
52
|
-
selection,
|
|
53
|
-
data: {
|
|
54
|
-
viewer: {
|
|
55
|
-
id: '1',
|
|
56
|
-
firstName: 'bob',
|
|
57
|
-
friends: [
|
|
58
|
-
{
|
|
59
|
-
id: '2',
|
|
60
|
-
firstName: 'jane',
|
|
61
|
-
},
|
|
62
|
-
null,
|
|
63
|
-
],
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
// make sure we can't resolve it already
|
|
69
|
-
expect(cache.read({ selection })).toMatchObject({
|
|
70
|
-
partial: false,
|
|
71
|
-
})
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
test('not partial with empty list', function () {
|
|
75
|
-
// instantiate the cache
|
|
76
|
-
const cache = new Cache(config)
|
|
77
|
-
|
|
78
|
-
const selection = {
|
|
79
|
-
viewer: {
|
|
80
|
-
type: 'User',
|
|
81
|
-
keyRaw: 'viewer',
|
|
82
|
-
fields: {
|
|
83
|
-
id: {
|
|
84
|
-
type: 'ID',
|
|
85
|
-
keyRaw: 'id',
|
|
86
|
-
},
|
|
87
|
-
firstName: {
|
|
88
|
-
type: 'String',
|
|
89
|
-
keyRaw: 'firstName',
|
|
90
|
-
},
|
|
91
|
-
friends: {
|
|
92
|
-
type: 'User',
|
|
93
|
-
keyRaw: 'friends',
|
|
94
|
-
fields: {
|
|
95
|
-
id: {
|
|
96
|
-
type: 'ID',
|
|
97
|
-
keyRaw: 'id',
|
|
98
|
-
},
|
|
99
|
-
firstName: {
|
|
100
|
-
type: 'String',
|
|
101
|
-
keyRaw: 'firstName',
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// make sure we can't resolve it already
|
|
110
|
-
expect(cache.read({ selection })).toMatchObject({
|
|
111
|
-
data: null,
|
|
112
|
-
partial: false,
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
// add some data to the cache
|
|
116
|
-
cache.write({
|
|
117
|
-
selection,
|
|
118
|
-
data: {
|
|
119
|
-
viewer: {
|
|
120
|
-
id: '1',
|
|
121
|
-
firstName: 'bob',
|
|
122
|
-
friends: [],
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
// make sure we get the right partial status
|
|
128
|
-
expect(cache.read({ selection })).toMatchObject({
|
|
129
|
-
partial: false,
|
|
130
|
-
})
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
test('partial with missing linked record', function () {
|
|
134
|
-
// instantiate the cache
|
|
135
|
-
const cache = new Cache(config)
|
|
136
|
-
|
|
137
|
-
const selection = {
|
|
138
|
-
viewer: {
|
|
139
|
-
type: 'User',
|
|
140
|
-
keyRaw: 'viewer',
|
|
141
|
-
fields: {
|
|
142
|
-
id: {
|
|
143
|
-
type: 'ID',
|
|
144
|
-
keyRaw: 'id',
|
|
145
|
-
},
|
|
146
|
-
firstName: {
|
|
147
|
-
type: 'String',
|
|
148
|
-
keyRaw: 'firstName',
|
|
149
|
-
},
|
|
150
|
-
parent: {
|
|
151
|
-
type: 'User',
|
|
152
|
-
keyRaw: 'parent',
|
|
153
|
-
fields: {
|
|
154
|
-
id: {
|
|
155
|
-
type: 'ID',
|
|
156
|
-
keyRaw: 'id',
|
|
157
|
-
},
|
|
158
|
-
firstName: {
|
|
159
|
-
type: 'String',
|
|
160
|
-
keyRaw: 'firstName',
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// make sure we can't resolve it already
|
|
169
|
-
expect(cache.read({ selection })).toMatchObject({
|
|
170
|
-
data: null,
|
|
171
|
-
partial: false,
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
// add some data to the cache
|
|
175
|
-
cache.write({
|
|
176
|
-
selection,
|
|
177
|
-
data: {
|
|
178
|
-
viewer: {
|
|
179
|
-
id: '1',
|
|
180
|
-
firstName: 'bob',
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
// make sure we get the right partial status
|
|
186
|
-
expect(cache.read({ selection })).toMatchObject({
|
|
187
|
-
partial: true,
|
|
188
|
-
})
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
test('partial with missing single field', function () {
|
|
192
|
-
// instantiate the cache
|
|
193
|
-
const cache = new Cache(config)
|
|
194
|
-
|
|
195
|
-
const selection = {
|
|
196
|
-
viewer: {
|
|
197
|
-
type: 'User',
|
|
198
|
-
keyRaw: 'viewer',
|
|
199
|
-
fields: {
|
|
200
|
-
id: {
|
|
201
|
-
type: 'ID',
|
|
202
|
-
keyRaw: 'id',
|
|
203
|
-
},
|
|
204
|
-
firstName: {
|
|
205
|
-
type: 'String',
|
|
206
|
-
keyRaw: 'firstName',
|
|
207
|
-
},
|
|
208
|
-
friends: {
|
|
209
|
-
type: 'User',
|
|
210
|
-
keyRaw: 'friends',
|
|
211
|
-
fields: {
|
|
212
|
-
id: {
|
|
213
|
-
type: 'ID',
|
|
214
|
-
keyRaw: 'id',
|
|
215
|
-
},
|
|
216
|
-
firstName: {
|
|
217
|
-
type: 'String',
|
|
218
|
-
keyRaw: 'firstName',
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// add some data to the cache
|
|
227
|
-
cache.write({
|
|
228
|
-
selection,
|
|
229
|
-
data: {
|
|
230
|
-
viewer: {
|
|
231
|
-
id: '1',
|
|
232
|
-
friends: [],
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
expect(cache.read({ selection })).toMatchObject({
|
|
238
|
-
partial: true,
|
|
239
|
-
})
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
test('partial missing data inside of linked list', function () {
|
|
243
|
-
// instantiate the cache
|
|
244
|
-
const cache = new Cache(config)
|
|
245
|
-
|
|
246
|
-
const selection = {
|
|
247
|
-
viewer: {
|
|
248
|
-
type: 'User',
|
|
249
|
-
keyRaw: 'viewer',
|
|
250
|
-
fields: {
|
|
251
|
-
id: {
|
|
252
|
-
type: 'ID',
|
|
253
|
-
keyRaw: 'id',
|
|
254
|
-
},
|
|
255
|
-
friends: {
|
|
256
|
-
type: 'User',
|
|
257
|
-
keyRaw: 'friends',
|
|
258
|
-
fields: {
|
|
259
|
-
id: {
|
|
260
|
-
type: 'ID',
|
|
261
|
-
keyRaw: 'id',
|
|
262
|
-
},
|
|
263
|
-
firstName: {
|
|
264
|
-
type: 'String',
|
|
265
|
-
keyRaw: 'firstName',
|
|
266
|
-
},
|
|
267
|
-
},
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// add some data to the cache with an incomplete set of values for an element
|
|
274
|
-
// inside of a list
|
|
275
|
-
cache.write({
|
|
276
|
-
selection,
|
|
277
|
-
data: {
|
|
278
|
-
viewer: {
|
|
279
|
-
id: '1',
|
|
280
|
-
friends: [{ id: '2', firstName: 'anthony' }, { id: '3' }],
|
|
281
|
-
},
|
|
282
|
-
},
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
expect(cache.read({ selection })).toMatchObject({
|
|
286
|
-
partial: true,
|
|
287
|
-
})
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
test('missing cursor of item in connection from operation should not trigger null cascade', function () {
|
|
291
|
-
// instantiate the cache
|
|
292
|
-
const cache = new Cache(config)
|
|
293
|
-
|
|
294
|
-
const selection = {
|
|
295
|
-
viewer: {
|
|
296
|
-
type: 'User',
|
|
297
|
-
keyRaw: 'viewer',
|
|
298
|
-
fields: {
|
|
299
|
-
id: {
|
|
300
|
-
type: 'ID',
|
|
301
|
-
keyRaw: 'id',
|
|
302
|
-
},
|
|
303
|
-
friends: {
|
|
304
|
-
type: 'User',
|
|
305
|
-
keyRaw: 'friends',
|
|
306
|
-
list: {
|
|
307
|
-
name: 'All_Users',
|
|
308
|
-
connection: true,
|
|
309
|
-
type: 'User',
|
|
310
|
-
},
|
|
311
|
-
fields: {
|
|
312
|
-
edges: {
|
|
313
|
-
type: 'UserEdge',
|
|
314
|
-
keyRaw: 'edges',
|
|
315
|
-
fields: {
|
|
316
|
-
cursor: {
|
|
317
|
-
type: 'Node',
|
|
318
|
-
keyRaw: 'cursor',
|
|
319
|
-
nullable: false,
|
|
320
|
-
},
|
|
321
|
-
node: {
|
|
322
|
-
type: 'Node',
|
|
323
|
-
keyRaw: 'node',
|
|
324
|
-
abstract: true,
|
|
325
|
-
fields: {
|
|
326
|
-
__typename: {
|
|
327
|
-
type: 'String',
|
|
328
|
-
keyRaw: '__typename',
|
|
329
|
-
},
|
|
330
|
-
id: {
|
|
331
|
-
type: 'ID',
|
|
332
|
-
keyRaw: 'id',
|
|
333
|
-
},
|
|
334
|
-
firstName: {
|
|
335
|
-
type: 'String',
|
|
336
|
-
keyRaw: 'firstName',
|
|
337
|
-
},
|
|
338
|
-
},
|
|
339
|
-
},
|
|
340
|
-
},
|
|
341
|
-
},
|
|
342
|
-
},
|
|
343
|
-
},
|
|
344
|
-
},
|
|
345
|
-
},
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// add some elements to the list already
|
|
349
|
-
cache.write({
|
|
350
|
-
selection,
|
|
351
|
-
data: {
|
|
352
|
-
viewer: {
|
|
353
|
-
id: '1',
|
|
354
|
-
friends: {
|
|
355
|
-
edges: [
|
|
356
|
-
{
|
|
357
|
-
node: {
|
|
358
|
-
__typename: 'User',
|
|
359
|
-
id: '2',
|
|
360
|
-
firstName: 'jane',
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
],
|
|
364
|
-
},
|
|
365
|
-
},
|
|
366
|
-
},
|
|
367
|
-
})
|
|
368
|
-
|
|
369
|
-
cache.subscribe({
|
|
370
|
-
set: vi.fn(),
|
|
371
|
-
selection,
|
|
372
|
-
rootType: 'Query',
|
|
373
|
-
})
|
|
374
|
-
|
|
375
|
-
// add some data to the cache with an incomplete set of values for an element
|
|
376
|
-
// inside of a list
|
|
377
|
-
cache.list('All_Users').prepend(
|
|
378
|
-
{
|
|
379
|
-
__typename: {
|
|
380
|
-
type: 'String',
|
|
381
|
-
keyRaw: '__typename',
|
|
382
|
-
},
|
|
383
|
-
id: {
|
|
384
|
-
type: 'ID',
|
|
385
|
-
keyRaw: 'id',
|
|
386
|
-
},
|
|
387
|
-
firstName: {
|
|
388
|
-
type: 'String',
|
|
389
|
-
keyRaw: 'firstName',
|
|
390
|
-
},
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
__typename: 'User',
|
|
394
|
-
id: '2',
|
|
395
|
-
firstName: 'Sally',
|
|
396
|
-
}
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
expect(cache.read({ selection })).not.toMatchObject({
|
|
400
|
-
data: {
|
|
401
|
-
viewer: {
|
|
402
|
-
friends: {
|
|
403
|
-
edges: expect.arrayContaining([null]),
|
|
404
|
-
},
|
|
405
|
-
},
|
|
406
|
-
},
|
|
407
|
-
})
|
|
408
|
-
})
|