houdini 0.17.7 → 0.17.9
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/.turbo/turbo-compile.log +2 -2
- package/.turbo/turbo-typedefs.log +2 -2
- package/CHANGELOG.md +9 -1
- package/build/cmd-cjs/index.js +124 -38
- package/build/cmd-esm/index.js +124 -38
- package/build/codegen-cjs/index.js +112 -36
- package/build/codegen-esm/index.js +112 -36
- package/build/lib/config.d.ts +3 -0
- package/build/lib-cjs/index.js +31 -12
- package/build/lib-esm/index.js +31 -12
- package/build/runtime/cache/cache.d.ts +1 -1
- package/build/runtime/cache/lists.d.ts +1 -1
- package/build/runtime/lib/config.d.ts +10 -2
- package/build/runtime/lib/types.d.ts +1 -0
- package/build/runtime-cjs/cache/cache.d.ts +1 -1
- package/build/runtime-cjs/cache/cache.js +6 -6
- package/build/runtime-cjs/cache/lists.d.ts +1 -1
- package/build/runtime-cjs/cache/lists.js +15 -6
- package/build/runtime-cjs/cache/tests/list.test.js +160 -70
- package/build/runtime-cjs/lib/config.d.ts +10 -2
- package/build/runtime-cjs/lib/types.d.ts +1 -0
- package/build/runtime-esm/cache/cache.d.ts +1 -1
- package/build/runtime-esm/cache/cache.js +6 -6
- package/build/runtime-esm/cache/lists.d.ts +1 -1
- package/build/runtime-esm/cache/lists.js +15 -6
- package/build/runtime-esm/cache/tests/list.test.js +160 -70
- package/build/runtime-esm/lib/config.d.ts +10 -2
- package/build/runtime-esm/lib/types.d.ts +1 -0
- package/build/test-cjs/index.js +122 -36
- package/build/test-esm/index.js +122 -36
- package/build/vite-cjs/index.js +122 -36
- package/build/vite-esm/index.js +122 -36
- package/package.json +1 -1
- package/src/codegen/generators/artifacts/artifacts.test.ts +268 -0
- package/src/codegen/generators/artifacts/operations.ts +31 -13
- package/src/codegen/generators/definitions/schema.test.ts +9 -0
- package/src/codegen/transforms/list.ts +0 -1
- package/src/codegen/transforms/paginate.test.ts +47 -0
- package/src/codegen/transforms/paginate.ts +28 -8
- package/src/codegen/transforms/schema.ts +5 -0
- package/src/codegen/validators/typeCheck.test.ts +56 -0
- package/src/codegen/validators/typeCheck.ts +66 -11
- package/src/lib/config.ts +11 -0
- package/src/runtime/cache/cache.ts +9 -6
- package/src/runtime/cache/lists.ts +24 -10
- package/src/runtime/cache/tests/list.test.ts +173 -66
- package/src/runtime/lib/config.ts +12 -2
- package/src/runtime/lib/types.ts +1 -0
|
@@ -320,6 +320,8 @@ export default async function typeCheck(
|
|
|
320
320
|
listTypes,
|
|
321
321
|
fragments,
|
|
322
322
|
}),
|
|
323
|
+
// checkMutationOperation
|
|
324
|
+
checkMutationOperation(config),
|
|
323
325
|
// pagination directive can only show up on nodes or the query type
|
|
324
326
|
nodeDirectives(config, [config.paginateDirective]),
|
|
325
327
|
// this replaces KnownArgumentNamesRule
|
|
@@ -415,29 +417,43 @@ const validateLists = ({
|
|
|
415
417
|
return
|
|
416
418
|
}
|
|
417
419
|
|
|
420
|
+
// Do we have the parentId another way?
|
|
421
|
+
let parentIdFound = false
|
|
418
422
|
// look for one of the list directives
|
|
419
423
|
directive = node.directives?.find(({ name }) => [
|
|
420
424
|
[config.listPrependDirective, config.listAppendDirective].includes(name.value),
|
|
421
425
|
])
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
+
if (directive) {
|
|
427
|
+
// find the argument holding the parent ID
|
|
428
|
+
let parentArg = directive.arguments?.find(
|
|
429
|
+
(arg) => arg.name.value === config.listDirectiveParentIDArg
|
|
426
430
|
)
|
|
431
|
+
if (parentArg) {
|
|
432
|
+
parentIdFound = true
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (parentIdFound) {
|
|
437
|
+
// parentId was found, so we're good to go
|
|
427
438
|
return
|
|
428
439
|
}
|
|
429
440
|
|
|
430
|
-
//
|
|
431
|
-
|
|
432
|
-
(
|
|
441
|
+
// look for allLists directive
|
|
442
|
+
const allLists = node.directives?.find(
|
|
443
|
+
({ name }) => config.listAllListsDirective === name.value
|
|
433
444
|
)
|
|
434
445
|
|
|
435
|
-
if
|
|
436
|
-
|
|
437
|
-
new graphql.GraphQLError('parentID is required for this list fragment')
|
|
438
|
-
)
|
|
446
|
+
// if there is the directive or it's
|
|
447
|
+
if (allLists || config.defaultListTarget === 'all') {
|
|
439
448
|
return
|
|
440
449
|
}
|
|
450
|
+
|
|
451
|
+
ctx.reportError(
|
|
452
|
+
new graphql.GraphQLError(
|
|
453
|
+
`For this list fragment, you need to add or @${config.listParentDirective} or @${config.listAllListsDirective} directive to specify the behavior`
|
|
454
|
+
)
|
|
455
|
+
)
|
|
456
|
+
return
|
|
441
457
|
},
|
|
442
458
|
// if we run into a directive that points to a list, make sure that list exists
|
|
443
459
|
Directive(node) {
|
|
@@ -925,6 +941,45 @@ function nodeDirectives(config: Config, directives: string[]) {
|
|
|
925
941
|
}
|
|
926
942
|
}
|
|
927
943
|
|
|
944
|
+
function checkMutationOperation(config: Config) {
|
|
945
|
+
return function (ctx: graphql.ValidationContext): graphql.ASTVisitor {
|
|
946
|
+
return {
|
|
947
|
+
FragmentSpread(node, _, __, ___, ancestors) {
|
|
948
|
+
const append = node.directives?.find(
|
|
949
|
+
(c) => c.name.value === config.listAppendDirective
|
|
950
|
+
)
|
|
951
|
+
|
|
952
|
+
const prepend = node.directives?.find(
|
|
953
|
+
(c) => c.name.value === config.listPrependDirective
|
|
954
|
+
)
|
|
955
|
+
if (append && prepend) {
|
|
956
|
+
ctx.reportError(
|
|
957
|
+
new graphql.GraphQLError(
|
|
958
|
+
`You can't apply both @${config.listPrependDirective} and @${config.listAppendDirective} at the same time`
|
|
959
|
+
)
|
|
960
|
+
)
|
|
961
|
+
return
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
const parentId = node.directives?.find(
|
|
965
|
+
(c) => c.name.value === config.listParentDirective
|
|
966
|
+
)
|
|
967
|
+
const allLists = node.directives?.find(
|
|
968
|
+
(c) => c.name.value === config.listAllListsDirective
|
|
969
|
+
)
|
|
970
|
+
if (parentId && allLists) {
|
|
971
|
+
ctx.reportError(
|
|
972
|
+
new graphql.GraphQLError(
|
|
973
|
+
`You can't apply both @${config.listParentDirective} and @${config.listAllListsDirective} at the same time`
|
|
974
|
+
)
|
|
975
|
+
)
|
|
976
|
+
return
|
|
977
|
+
}
|
|
978
|
+
},
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
928
983
|
export function getAndVerifyNodeInterface(config: Config): graphql.GraphQLInterfaceType | null {
|
|
929
984
|
const { schema } = config
|
|
930
985
|
|
package/src/lib/config.ts
CHANGED
|
@@ -38,6 +38,8 @@ export class Config {
|
|
|
38
38
|
cacheBufferSize?: number
|
|
39
39
|
defaultCachePolicy: CachePolicy
|
|
40
40
|
defaultPartial: boolean
|
|
41
|
+
internalListPosition: 'first' | 'last'
|
|
42
|
+
defaultListTarget: 'all' | null = null
|
|
41
43
|
definitionsFolder?: string
|
|
42
44
|
newSchema: string = ''
|
|
43
45
|
newDocuments: string = ''
|
|
@@ -77,6 +79,8 @@ export class Config {
|
|
|
77
79
|
definitionsPath,
|
|
78
80
|
defaultCachePolicy = CachePolicy.CacheOrNetwork,
|
|
79
81
|
defaultPartial = false,
|
|
82
|
+
defaultListPosition = 'append',
|
|
83
|
+
defaultListTarget = null,
|
|
80
84
|
defaultKeys,
|
|
81
85
|
types = {},
|
|
82
86
|
logLevel,
|
|
@@ -116,6 +120,8 @@ export class Config {
|
|
|
116
120
|
this.cacheBufferSize = cacheBufferSize
|
|
117
121
|
this.defaultCachePolicy = defaultCachePolicy
|
|
118
122
|
this.defaultPartial = defaultPartial
|
|
123
|
+
this.internalListPosition = defaultListPosition === 'append' ? 'last' : 'first'
|
|
124
|
+
this.defaultListTarget == defaultListTarget
|
|
119
125
|
this.definitionsFolder = definitionsPath
|
|
120
126
|
this.logLevel = ((logLevel as LogLevel) || LogLevel.Summary).toLowerCase() as LogLevel
|
|
121
127
|
this.disableMasking = disableMasking
|
|
@@ -470,6 +476,10 @@ export class Config {
|
|
|
470
476
|
return 'parentID'
|
|
471
477
|
}
|
|
472
478
|
|
|
479
|
+
get listAllListsDirective() {
|
|
480
|
+
return 'allLists'
|
|
481
|
+
}
|
|
482
|
+
|
|
473
483
|
get listNameArg() {
|
|
474
484
|
return 'name'
|
|
475
485
|
}
|
|
@@ -578,6 +588,7 @@ export class Config {
|
|
|
578
588
|
this.listPrependDirective,
|
|
579
589
|
this.listAppendDirective,
|
|
580
590
|
this.listDirectiveParentIDArg,
|
|
591
|
+
this.listAllListsDirective,
|
|
581
592
|
this.whenDirective,
|
|
582
593
|
this.whenNotDirective,
|
|
583
594
|
this.argumentsDirective,
|
|
@@ -110,8 +110,8 @@ export class Cache {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
// return the list handler to mutate a named list in the cache
|
|
113
|
-
list(name: string, parentID?: string
|
|
114
|
-
const handler = this._internal_unstable.lists.get(name, parentID)
|
|
113
|
+
list(name: string, parentID?: string, allLists?: boolean): ListCollection {
|
|
114
|
+
const handler = this._internal_unstable.lists.get(name, parentID, allLists)
|
|
115
115
|
if (!handler) {
|
|
116
116
|
throw new Error(
|
|
117
117
|
`Cannot find list with name: ${name}${
|
|
@@ -570,7 +570,10 @@ class CacheInternal {
|
|
|
570
570
|
}
|
|
571
571
|
|
|
572
572
|
// if the necessary list doesn't exist, don't do anything
|
|
573
|
-
if (
|
|
573
|
+
if (
|
|
574
|
+
operation.list &&
|
|
575
|
+
!this.lists.get(operation.list, parentID, operation.target === 'all')
|
|
576
|
+
) {
|
|
574
577
|
continue
|
|
575
578
|
}
|
|
576
579
|
|
|
@@ -585,7 +588,7 @@ class CacheInternal {
|
|
|
585
588
|
operation.list
|
|
586
589
|
) {
|
|
587
590
|
this.cache
|
|
588
|
-
.list(operation.list, parentID)
|
|
591
|
+
.list(operation.list, parentID, operation.target === 'all')
|
|
589
592
|
.when(operation.when)
|
|
590
593
|
.addToList(fields, target, variables, operation.position || 'last')
|
|
591
594
|
}
|
|
@@ -598,7 +601,7 @@ class CacheInternal {
|
|
|
598
601
|
operation.list
|
|
599
602
|
) {
|
|
600
603
|
this.cache
|
|
601
|
-
.list(operation.list, parentID)
|
|
604
|
+
.list(operation.list, parentID, operation.target === 'all')
|
|
602
605
|
.when(operation.when)
|
|
603
606
|
.remove(target, variables)
|
|
604
607
|
}
|
|
@@ -624,7 +627,7 @@ class CacheInternal {
|
|
|
624
627
|
operation.list
|
|
625
628
|
) {
|
|
626
629
|
this.cache
|
|
627
|
-
.list(operation.list, parentID)
|
|
630
|
+
.list(operation.list, parentID, operation.target === 'all')
|
|
628
631
|
.when(operation.when)
|
|
629
632
|
.toggleElement(fields, target, variables, operation.position || 'last')
|
|
630
633
|
}
|
|
@@ -16,7 +16,7 @@ export class ListManager {
|
|
|
16
16
|
|
|
17
17
|
private listsByField: Map<string, Map<string, List[]>> = new Map()
|
|
18
18
|
|
|
19
|
-
get(listName: string, id?: string
|
|
19
|
+
get(listName: string, id?: string, allLists?: boolean) {
|
|
20
20
|
const matches = this.lists.get(listName)
|
|
21
21
|
|
|
22
22
|
// if we don't have a list by that name, we're done
|
|
@@ -24,11 +24,29 @@ export class ListManager {
|
|
|
24
24
|
return null
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// if we want to update all list, return all matches
|
|
28
|
+
if (allLists) {
|
|
29
|
+
return new ListCollection(
|
|
30
|
+
Array.from(matches, ([key, value]) => [...value.lists]).flat()
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
27
34
|
const head = [...matches.values()][0]
|
|
28
35
|
|
|
36
|
+
// the provided id won't match the cache's ID so we have to compute the internal ID, using
|
|
37
|
+
// one of the matches to figure out the type of the list element
|
|
38
|
+
const { recordType } = head.lists[0]
|
|
39
|
+
const parentID = id ? this.cache._internal_unstable.id(recordType || '', id)! : this.rootID
|
|
40
|
+
|
|
29
41
|
// if there is only one list with that name, return it
|
|
30
42
|
if (matches?.size === 1) {
|
|
31
|
-
|
|
43
|
+
// if there is no provided id, just use the first one
|
|
44
|
+
if (!id) {
|
|
45
|
+
return head
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// otherwise we're only safe to use the head if it matches the parentID
|
|
49
|
+
return parentID === Array.from(matches.keys())[0] ? head : null
|
|
32
50
|
}
|
|
33
51
|
|
|
34
52
|
// there are multiple versions of the list so the user must
|
|
@@ -36,17 +54,13 @@ export class ListManager {
|
|
|
36
54
|
// it would have been caught in the size === 1 check above since
|
|
37
55
|
// root's ID is fixed
|
|
38
56
|
if (!id) {
|
|
39
|
-
|
|
40
|
-
`Found multiple instances of "${listName}". Please provide
|
|
41
|
-
`
|
|
57
|
+
console.error(
|
|
58
|
+
`Found multiple instances of "${listName}". Please provide one of @parentID or @allLists directives to ` +
|
|
59
|
+
`help identify which list you want modify. For more information, visit this guide: https://www.houdinigraphql.com/api/graphql#parentidvalue-string `
|
|
42
60
|
)
|
|
61
|
+
return null
|
|
43
62
|
}
|
|
44
63
|
|
|
45
|
-
// the provided id won't match the cache's ID so we have to compute the internal ID, using
|
|
46
|
-
// one of the matches to figure out the type of the list element
|
|
47
|
-
const { recordType } = head.lists[0]
|
|
48
|
-
const parentID = id ? this.cache._internal_unstable.id(recordType || '', id)! : this.rootID
|
|
49
|
-
|
|
50
64
|
// return the list pointing to the correct parent
|
|
51
65
|
return this.lists.get(listName)?.get(parentID)
|
|
52
66
|
}
|
|
@@ -1624,10 +1624,6 @@ test('append operation', function () {
|
|
|
1624
1624
|
{
|
|
1625
1625
|
action: 'insert',
|
|
1626
1626
|
list: 'All_Users',
|
|
1627
|
-
parentID: {
|
|
1628
|
-
kind: 'String',
|
|
1629
|
-
value: cache._internal_unstable.id('User', '1')!,
|
|
1630
|
-
},
|
|
1631
1627
|
},
|
|
1632
1628
|
],
|
|
1633
1629
|
fields: {
|
|
@@ -1646,7 +1642,7 @@ test('append operation', function () {
|
|
|
1646
1642
|
})
|
|
1647
1643
|
|
|
1648
1644
|
// make sure we just added to the list
|
|
1649
|
-
expect([...cache.list('All_Users',
|
|
1645
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(1)
|
|
1650
1646
|
})
|
|
1651
1647
|
|
|
1652
1648
|
test('append from list', function () {
|
|
@@ -1716,10 +1712,6 @@ test('append from list', function () {
|
|
|
1716
1712
|
{
|
|
1717
1713
|
action: 'insert',
|
|
1718
1714
|
list: 'All_Users',
|
|
1719
|
-
parentID: {
|
|
1720
|
-
kind: 'String',
|
|
1721
|
-
value: cache._internal_unstable.id('User', '1')!,
|
|
1722
|
-
},
|
|
1723
1715
|
},
|
|
1724
1716
|
],
|
|
1725
1717
|
fields: {
|
|
@@ -1736,7 +1728,7 @@ test('append from list', function () {
|
|
|
1736
1728
|
})
|
|
1737
1729
|
|
|
1738
1730
|
// make sure we just added to the list
|
|
1739
|
-
expect([...cache.list('All_Users',
|
|
1731
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(2)
|
|
1740
1732
|
})
|
|
1741
1733
|
|
|
1742
1734
|
test('toggle list', function () {
|
|
@@ -1823,10 +1815,6 @@ test('toggle list', function () {
|
|
|
1823
1815
|
{
|
|
1824
1816
|
action: 'toggle',
|
|
1825
1817
|
list: 'All_Users',
|
|
1826
|
-
parentID: {
|
|
1827
|
-
kind: 'String',
|
|
1828
|
-
value: cache._internal_unstable.id('User', '1')!,
|
|
1829
|
-
},
|
|
1830
1818
|
},
|
|
1831
1819
|
],
|
|
1832
1820
|
fields: {
|
|
@@ -1841,23 +1829,15 @@ test('toggle list', function () {
|
|
|
1841
1829
|
// write some data to a different location with a new user
|
|
1842
1830
|
// that should be added to the list
|
|
1843
1831
|
cache.write({ selection: toggleSelection, data: { newUser: { id: '3' } } })
|
|
1844
|
-
expect([...cache.list('All_Users',
|
|
1845
|
-
'User:5',
|
|
1846
|
-
'User:3',
|
|
1847
|
-
])
|
|
1832
|
+
expect([...cache.list('All_Users', '1')]).toEqual(['User:5', 'User:3'])
|
|
1848
1833
|
|
|
1849
1834
|
// toggle the user again to remove the user
|
|
1850
1835
|
cache.write({ selection: toggleSelection, data: { newUser: { id: '3' } } })
|
|
1851
|
-
expect([...cache.list('All_Users',
|
|
1852
|
-
'User:5',
|
|
1853
|
-
])
|
|
1836
|
+
expect([...cache.list('All_Users', '1')]).toEqual(['User:5'])
|
|
1854
1837
|
|
|
1855
1838
|
// toggle the user again to add the user back
|
|
1856
1839
|
cache.write({ selection: toggleSelection, data: { newUser: { id: '3' } } })
|
|
1857
|
-
expect([...cache.list('All_Users',
|
|
1858
|
-
'User:5',
|
|
1859
|
-
'User:3',
|
|
1860
|
-
])
|
|
1840
|
+
expect([...cache.list('All_Users', '1')]).toEqual(['User:5', 'User:3'])
|
|
1861
1841
|
})
|
|
1862
1842
|
|
|
1863
1843
|
test('append when operation', function () {
|
|
@@ -1933,10 +1913,6 @@ test('append when operation', function () {
|
|
|
1933
1913
|
{
|
|
1934
1914
|
action: 'insert',
|
|
1935
1915
|
list: 'All_Users',
|
|
1936
|
-
parentID: {
|
|
1937
|
-
kind: 'String',
|
|
1938
|
-
value: cache._internal_unstable.id('User', '1')!,
|
|
1939
|
-
},
|
|
1940
1916
|
when: {
|
|
1941
1917
|
must: {
|
|
1942
1918
|
value: 'not-foo',
|
|
@@ -1960,7 +1936,7 @@ test('append when operation', function () {
|
|
|
1960
1936
|
})
|
|
1961
1937
|
|
|
1962
1938
|
// make sure we just added to the list
|
|
1963
|
-
expect([...cache.list('All_Users',
|
|
1939
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(0)
|
|
1964
1940
|
})
|
|
1965
1941
|
|
|
1966
1942
|
test('prepend when operation', function () {
|
|
@@ -2036,10 +2012,6 @@ test('prepend when operation', function () {
|
|
|
2036
2012
|
{
|
|
2037
2013
|
action: 'insert',
|
|
2038
2014
|
list: 'All_Users',
|
|
2039
|
-
parentID: {
|
|
2040
|
-
kind: 'String',
|
|
2041
|
-
value: cache._internal_unstable.id('User', '1')!,
|
|
2042
|
-
},
|
|
2043
2015
|
position: 'first',
|
|
2044
2016
|
when: {
|
|
2045
2017
|
must: {
|
|
@@ -2064,7 +2036,7 @@ test('prepend when operation', function () {
|
|
|
2064
2036
|
})
|
|
2065
2037
|
|
|
2066
2038
|
// make sure we just added to the list
|
|
2067
|
-
expect([...cache.list('All_Users',
|
|
2039
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(0)
|
|
2068
2040
|
})
|
|
2069
2041
|
|
|
2070
2042
|
test('prepend operation', function () {
|
|
@@ -2154,10 +2126,6 @@ test('prepend operation', function () {
|
|
|
2154
2126
|
{
|
|
2155
2127
|
action: 'insert',
|
|
2156
2128
|
list: 'All_Users',
|
|
2157
|
-
parentID: {
|
|
2158
|
-
kind: 'String',
|
|
2159
|
-
value: cache._internal_unstable.id('User', '1')!,
|
|
2160
|
-
},
|
|
2161
2129
|
position: 'first',
|
|
2162
2130
|
},
|
|
2163
2131
|
],
|
|
@@ -2177,10 +2145,7 @@ test('prepend operation', function () {
|
|
|
2177
2145
|
})
|
|
2178
2146
|
|
|
2179
2147
|
// make sure we just added to the list
|
|
2180
|
-
expect([...cache.list('All_Users',
|
|
2181
|
-
'User:3',
|
|
2182
|
-
'User:2',
|
|
2183
|
-
])
|
|
2148
|
+
expect([...cache.list('All_Users', '1')]).toEqual(['User:3', 'User:2'])
|
|
2184
2149
|
})
|
|
2185
2150
|
|
|
2186
2151
|
test('remove operation', function () {
|
|
@@ -2265,10 +2230,6 @@ test('remove operation', function () {
|
|
|
2265
2230
|
{
|
|
2266
2231
|
action: 'remove',
|
|
2267
2232
|
list: 'All_Users',
|
|
2268
|
-
parentID: {
|
|
2269
|
-
kind: 'String',
|
|
2270
|
-
value: cache._internal_unstable.id('User', '1')!,
|
|
2271
|
-
},
|
|
2272
2233
|
},
|
|
2273
2234
|
],
|
|
2274
2235
|
fields: {
|
|
@@ -2287,7 +2248,7 @@ test('remove operation', function () {
|
|
|
2287
2248
|
})
|
|
2288
2249
|
|
|
2289
2250
|
// make sure we removed the element from the list
|
|
2290
|
-
expect([...cache.list('All_Users',
|
|
2251
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(0)
|
|
2291
2252
|
})
|
|
2292
2253
|
|
|
2293
2254
|
test('remove operation from list', function () {
|
|
@@ -2375,10 +2336,6 @@ test('remove operation from list', function () {
|
|
|
2375
2336
|
{
|
|
2376
2337
|
action: 'remove',
|
|
2377
2338
|
list: 'All_Users',
|
|
2378
|
-
parentID: {
|
|
2379
|
-
kind: 'String',
|
|
2380
|
-
value: cache._internal_unstable.id('User', '1')!,
|
|
2381
|
-
},
|
|
2382
2339
|
},
|
|
2383
2340
|
],
|
|
2384
2341
|
fields: {
|
|
@@ -2395,7 +2352,7 @@ test('remove operation from list', function () {
|
|
|
2395
2352
|
})
|
|
2396
2353
|
|
|
2397
2354
|
// make sure we removed the element from the list
|
|
2398
|
-
expect([...cache.list('All_Users',
|
|
2355
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(0)
|
|
2399
2356
|
})
|
|
2400
2357
|
|
|
2401
2358
|
test('delete operation', function () {
|
|
@@ -2498,7 +2455,7 @@ test('delete operation', function () {
|
|
|
2498
2455
|
})
|
|
2499
2456
|
|
|
2500
2457
|
// make sure we removed the element from the list
|
|
2501
|
-
expect([...cache.list('All_Users',
|
|
2458
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(0)
|
|
2502
2459
|
|
|
2503
2460
|
expect(cache._internal_unstable.storage.topLayer.operations['User:2'].deleted).toBeTruthy()
|
|
2504
2461
|
})
|
|
@@ -2606,7 +2563,7 @@ test('delete operation from list', function () {
|
|
|
2606
2563
|
})
|
|
2607
2564
|
|
|
2608
2565
|
// make sure we removed the element from the list
|
|
2609
|
-
expect([...cache.list('All_Users',
|
|
2566
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(0)
|
|
2610
2567
|
|
|
2611
2568
|
expect(cache._internal_unstable.storage.topLayer.operations['User:2'].deleted).toBeTruthy()
|
|
2612
2569
|
expect(cache._internal_unstable.storage.topLayer.operations['User:3'].deleted).toBeTruthy()
|
|
@@ -2753,7 +2710,7 @@ test('delete operation from connection', function () {
|
|
|
2753
2710
|
})
|
|
2754
2711
|
|
|
2755
2712
|
// make sure we removed the element from the list
|
|
2756
|
-
expect([...cache.list('All_Users',
|
|
2713
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(0)
|
|
2757
2714
|
expect(cache._internal_unstable.storage.topLayer.operations['User:2'].deleted).toBeTruthy()
|
|
2758
2715
|
})
|
|
2759
2716
|
|
|
@@ -3225,10 +3182,6 @@ test('list operations fail silently', function () {
|
|
|
3225
3182
|
{
|
|
3226
3183
|
action: 'insert',
|
|
3227
3184
|
list: 'All_Users',
|
|
3228
|
-
parentID: {
|
|
3229
|
-
kind: 'String',
|
|
3230
|
-
value: cache._internal_unstable.id('User', '1')!,
|
|
3231
|
-
},
|
|
3232
3185
|
},
|
|
3233
3186
|
],
|
|
3234
3187
|
fields: {
|
|
@@ -3399,7 +3352,7 @@ test('parentID must be passed if there are multiple instances of a list handler'
|
|
|
3399
3352
|
// instantiate a cache
|
|
3400
3353
|
const cache = new Cache(config)
|
|
3401
3354
|
|
|
3402
|
-
const friendsSelection = {
|
|
3355
|
+
const friendsSelection: SubscriptionSelection = {
|
|
3403
3356
|
friends: {
|
|
3404
3357
|
type: 'User',
|
|
3405
3358
|
keyRaw: 'friends',
|
|
@@ -3471,11 +3424,73 @@ test('parentID must be passed if there are multiple instances of a list handler'
|
|
|
3471
3424
|
{}
|
|
3472
3425
|
)
|
|
3473
3426
|
|
|
3474
|
-
//
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3427
|
+
// append a value to the store
|
|
3428
|
+
const writeSelectionNoParentID: SubscriptionSelection = {
|
|
3429
|
+
user: {
|
|
3430
|
+
type: 'User',
|
|
3431
|
+
keyRaw: 'user',
|
|
3432
|
+
operations: [
|
|
3433
|
+
{
|
|
3434
|
+
action: 'insert',
|
|
3435
|
+
list: 'All_Users',
|
|
3436
|
+
},
|
|
3437
|
+
],
|
|
3438
|
+
fields: {
|
|
3439
|
+
id: {
|
|
3440
|
+
type: 'ID',
|
|
3441
|
+
keyRaw: 'id',
|
|
3442
|
+
},
|
|
3443
|
+
firstName: {
|
|
3444
|
+
type: 'String',
|
|
3445
|
+
keyRaw: 'firstName',
|
|
3446
|
+
},
|
|
3447
|
+
},
|
|
3448
|
+
},
|
|
3449
|
+
}
|
|
3450
|
+
const writeSelectionWithParentID: SubscriptionSelection = {
|
|
3451
|
+
user: {
|
|
3452
|
+
type: 'User',
|
|
3453
|
+
keyRaw: 'user',
|
|
3454
|
+
operations: [
|
|
3455
|
+
{
|
|
3456
|
+
action: 'insert',
|
|
3457
|
+
list: 'All_Users',
|
|
3458
|
+
parentID: {
|
|
3459
|
+
kind: 'String',
|
|
3460
|
+
value: '1',
|
|
3461
|
+
},
|
|
3462
|
+
},
|
|
3463
|
+
],
|
|
3464
|
+
fields: {
|
|
3465
|
+
id: {
|
|
3466
|
+
type: 'ID',
|
|
3467
|
+
keyRaw: 'id',
|
|
3468
|
+
},
|
|
3469
|
+
firstName: {
|
|
3470
|
+
type: 'String',
|
|
3471
|
+
keyRaw: 'firstName',
|
|
3472
|
+
},
|
|
3473
|
+
},
|
|
3474
|
+
},
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
// write the value without a parent ID
|
|
3478
|
+
cache.write({
|
|
3479
|
+
selection: writeSelectionNoParentID,
|
|
3480
|
+
data: { user: { id: '2', firstName: 'test' } },
|
|
3481
|
+
})
|
|
3482
|
+
// make sure we didn't modify the lists
|
|
3483
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(1)
|
|
3484
|
+
expect([...cache.list('All_Users', '2')]).toHaveLength(0)
|
|
3485
|
+
|
|
3486
|
+
// write the value with a parent ID
|
|
3487
|
+
cache.write({
|
|
3488
|
+
selection: writeSelectionWithParentID,
|
|
3489
|
+
data: { user: { id: '2', firstName: 'test' } },
|
|
3490
|
+
})
|
|
3491
|
+
// make sure we modified the correct list
|
|
3492
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(2)
|
|
3493
|
+
expect([...cache.list('All_Users', '2')]).toHaveLength(0)
|
|
3479
3494
|
})
|
|
3480
3495
|
|
|
3481
3496
|
test('append in abstract list', function () {
|
|
@@ -3745,3 +3760,95 @@ test('list operations on interface fields without a well defined parent update t
|
|
|
3745
3760
|
},
|
|
3746
3761
|
})
|
|
3747
3762
|
})
|
|
3763
|
+
|
|
3764
|
+
test("parentID ignores single lists that don't match", function () {
|
|
3765
|
+
// instantiate a cache
|
|
3766
|
+
const cache = new Cache(config)
|
|
3767
|
+
|
|
3768
|
+
// create a list we will add to
|
|
3769
|
+
cache.write({
|
|
3770
|
+
selection: {
|
|
3771
|
+
viewer: {
|
|
3772
|
+
type: 'User',
|
|
3773
|
+
keyRaw: 'viewer',
|
|
3774
|
+
fields: {
|
|
3775
|
+
id: {
|
|
3776
|
+
type: 'ID',
|
|
3777
|
+
keyRaw: 'id',
|
|
3778
|
+
},
|
|
3779
|
+
},
|
|
3780
|
+
},
|
|
3781
|
+
},
|
|
3782
|
+
data: {
|
|
3783
|
+
viewer: {
|
|
3784
|
+
id: '1',
|
|
3785
|
+
},
|
|
3786
|
+
},
|
|
3787
|
+
})
|
|
3788
|
+
|
|
3789
|
+
// subscribe to the data to register the list
|
|
3790
|
+
cache.subscribe(
|
|
3791
|
+
{
|
|
3792
|
+
rootType: 'User',
|
|
3793
|
+
selection: {
|
|
3794
|
+
friends: {
|
|
3795
|
+
type: 'User',
|
|
3796
|
+
keyRaw: 'friends',
|
|
3797
|
+
list: {
|
|
3798
|
+
name: 'All_Users',
|
|
3799
|
+
connection: false,
|
|
3800
|
+
type: 'User',
|
|
3801
|
+
},
|
|
3802
|
+
fields: {
|
|
3803
|
+
id: {
|
|
3804
|
+
type: 'ID',
|
|
3805
|
+
keyRaw: 'id',
|
|
3806
|
+
},
|
|
3807
|
+
firstName: {
|
|
3808
|
+
type: 'String',
|
|
3809
|
+
keyRaw: 'firstName',
|
|
3810
|
+
},
|
|
3811
|
+
},
|
|
3812
|
+
},
|
|
3813
|
+
},
|
|
3814
|
+
parentID: cache._internal_unstable.id('User', '1')!,
|
|
3815
|
+
set: vi.fn(),
|
|
3816
|
+
},
|
|
3817
|
+
{}
|
|
3818
|
+
)
|
|
3819
|
+
|
|
3820
|
+
// write some data to a different location with a new user
|
|
3821
|
+
// that should be added to the list
|
|
3822
|
+
cache.write({
|
|
3823
|
+
selection: {
|
|
3824
|
+
newUser: {
|
|
3825
|
+
type: 'User',
|
|
3826
|
+
keyRaw: 'newUser',
|
|
3827
|
+
operations: [
|
|
3828
|
+
{
|
|
3829
|
+
action: 'insert',
|
|
3830
|
+
list: 'All_Users',
|
|
3831
|
+
parentID: {
|
|
3832
|
+
kind: 'String',
|
|
3833
|
+
value: '2',
|
|
3834
|
+
},
|
|
3835
|
+
},
|
|
3836
|
+
],
|
|
3837
|
+
fields: {
|
|
3838
|
+
id: {
|
|
3839
|
+
type: 'ID',
|
|
3840
|
+
keyRaw: 'id',
|
|
3841
|
+
},
|
|
3842
|
+
},
|
|
3843
|
+
},
|
|
3844
|
+
},
|
|
3845
|
+
data: {
|
|
3846
|
+
newUser: {
|
|
3847
|
+
id: '3',
|
|
3848
|
+
},
|
|
3849
|
+
},
|
|
3850
|
+
})
|
|
3851
|
+
|
|
3852
|
+
// make sure we just added to the list
|
|
3853
|
+
expect([...cache.list('All_Users', '1')]).toHaveLength(0)
|
|
3854
|
+
})
|
|
@@ -100,13 +100,13 @@ export type ConfigFile = {
|
|
|
100
100
|
definitionsPath?: string
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
|
-
* One of "kit" or "svelte". Used to tell the preprocessor what kind of loading paradigm to generate for you. (default: kit)
|
|
103
|
+
* One of "kit" or "svelte". Used to tell the preprocessor what kind of loading paradigm to generate for you. (default: `kit`)
|
|
104
104
|
* @deprecated please follow the steps here: http://www.houdinigraphql.com/guides/release-notes#0170
|
|
105
105
|
*/
|
|
106
106
|
framework?: 'kit' | 'svelte'
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
|
-
* One of "esm" or "commonjs". Tells the artifact generator what kind of modules to create. (default: esm)
|
|
109
|
+
* One of "esm" or "commonjs". Tells the artifact generator what kind of modules to create. (default: `esm`)
|
|
110
110
|
*/
|
|
111
111
|
module?: 'esm' | 'commonjs'
|
|
112
112
|
|
|
@@ -125,6 +125,16 @@ export type ConfigFile = {
|
|
|
125
125
|
*/
|
|
126
126
|
defaultPartial?: boolean
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Specifies whether mutations should append or prepend list. For more information: https://www.houdinigraphql.com/api/graphql (default: `append`)
|
|
130
|
+
*/
|
|
131
|
+
defaultListPosition?: 'append' | 'prepend'
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Specifies whether mutation should apply a specific target list. When you set `all`, it's like adding the directive `@allLists` to all _insert fragment (default: `null`)
|
|
135
|
+
*/
|
|
136
|
+
defaultListTarget?: 'all' | null
|
|
137
|
+
|
|
128
138
|
/**
|
|
129
139
|
* A list of fields to use when computing a record’s id. The default value is ['id']. For more information: https://www.houdinigraphql.com/guides/caching-data#custom-ids
|
|
130
140
|
*/
|