Skip to content

Commit 6903c0e

Browse files
niieaniJames Baxley
authored and
James Baxley
committed
fix(apollo-cache-inmemory): track typename in IdValue and replace underlying objects when it changes (#3159)
* fix(apollo-cache-inmemory): track typename in field id values and allow missing id when it changes There is an edge case bug with types that are of a Union type of: `{ id, __typename: 'First' }` and `{ __typename: 'Second' }` (without the `id` field). In such a case, if we first retrieve a result with `First` and then re-query when the response contains the other type (`Second`), Apollo would throw an error that the field is now missing an `id`, which was previously present. This would be correct if the object was of the same type, however we cannot know whether another type (`Second`) even contains an `id` field in the schema in the first place (here, it didn't). This commit adds support for tracking typenames to the `IdValue` and should such a case occur, it fully replaces fields with autogenerated names in case their underlying types have changed, after being re-queried. * chore(tests): add typenames to IdValues created in tests * chore(tests): use snapshots to simplify testing changes to the Cache implementation * doc(apollo-cache-inmemory): add CHANGELOG entry * refactor(apollo-cache-inmemory): try to address benchmark drop * doc(apollo-cache-inmemory): add contributor * chore(apollo-utilities): add a warning about toIdValue signature change * chore(apollo-utilities): update flow typings * chore(apollo-utilities): update flow typings * Update package.json * refactor(apollo-utilities): change toIdValue helper signature to remove breaking change
1 parent bdfcc93 commit 6903c0e

18 files changed

+1063
-597
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
{
4747
"name": "apollo-utilities",
4848
"path": "./packages/apollo-utilities/lib/bundle.min.js",
49-
"maxSize": "4.75 kB"
49+
"maxSize": "5 kB"
5050
},
5151
{
5252
"name": "graphql-anywhere",

packages/apollo-cache-inmemory/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Change log
22

33
### vNext
4+
- Fix an edge case where fields that were unions of two types, one with an `id`,
5+
one without an `id`, would cause the cache to throw while saving the result [#3159](https://github.com/apollographql/apollo-client/pull/3159)
46
- Map coverage to original source
57
- Fixed bug with cacheRedirects not getting attached [#3016](https://github.com/apollographql/apollo-client/pull/3016)
68

packages/apollo-cache-inmemory/package.json

+7-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"James Baxley <james@meteor.com>",
88
"Jonas Helfer <jonas@helfer.email>",
99
"Sashko Stubailo <sashko@stubailo.com>",
10-
"James Burgess <jamesmillerburgess@gmail.com>"
10+
"James Burgess <jamesmillerburgess@gmail.com>",
11+
"Bazyli Brzóska <bazyli.brzoska@gmail.com>"
1112
],
1213
"license": "MIT",
1314
"main": "./lib/bundle.umd.js",
@@ -33,8 +34,10 @@
3334
"watch": "tsc -w -p .",
3435
"clean": "rimraf coverage/* && rimraf lib/*",
3536
"prepublishOnly": "npm run build",
36-
"build:browser": "browserify ./lib/bundle.umd.js --i apollo-cache --i apollo-utilities --i graphql -o=./lib/bundle.js && npm run minify:browser",
37-
"minify:browser": "uglifyjs -c -m -o ./lib/bundle.min.js -- ./lib/bundle.js",
37+
"build:browser":
38+
"browserify ./lib/bundle.umd.js --i apollo-cache --i apollo-utilities --i graphql -o=./lib/bundle.js && npm run minify:browser",
39+
"minify:browser":
40+
"uglifyjs -c -m -o ./lib/bundle.min.js -- ./lib/bundle.js",
3841
"filesize": "npm run build:browser"
3942
},
4043
"dependencies": {
@@ -66,12 +69,7 @@
6669
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
6770
},
6871
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
69-
"moduleFileExtensions": [
70-
"ts",
71-
"tsx",
72-
"js",
73-
"json"
74-
],
72+
"moduleFileExtensions": ["ts", "tsx", "js", "json"],
7573
"mapCoverage": true
7674
}
7775
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[
4+
`Cache writeFragment will write some deeply nested data into the store at any id 1`
5+
] = `
6+
Object {
7+
"bar": Object {
8+
"i": 7,
9+
},
10+
"foo": Object {
11+
"e": 4,
12+
"h": Object {
13+
"generated": false,
14+
"id": "bar",
15+
"type": "id",
16+
"typename": undefined,
17+
},
18+
},
19+
}
20+
`;
21+
22+
exports[
23+
`Cache writeFragment will write some deeply nested data into the store at any id 2`
24+
] = `
25+
Object {
26+
"bar": Object {
27+
"i": 7,
28+
"j": 8,
29+
"k": 9,
30+
},
31+
"foo": Object {
32+
"e": 4,
33+
"f": 5,
34+
"g": 6,
35+
"h": Object {
36+
"generated": false,
37+
"id": "bar",
38+
"type": "id",
39+
"typename": undefined,
40+
},
41+
},
42+
}
43+
`;
44+
45+
exports[
46+
`Cache writeFragment will write some deeply nested data into the store at any id 3`
47+
] = `
48+
Object {
49+
"bar": Object {
50+
"i": 10,
51+
"j": 8,
52+
"k": 9,
53+
},
54+
"foo": Object {
55+
"e": 4,
56+
"f": 5,
57+
"g": 6,
58+
"h": Object {
59+
"generated": false,
60+
"id": "bar",
61+
"type": "id",
62+
"typename": undefined,
63+
},
64+
},
65+
}
66+
`;
67+
68+
exports[
69+
`Cache writeFragment will write some deeply nested data into the store at any id 4`
70+
] = `
71+
Object {
72+
"bar": Object {
73+
"i": 10,
74+
"j": 11,
75+
"k": 12,
76+
},
77+
"foo": Object {
78+
"e": 4,
79+
"f": 5,
80+
"g": 6,
81+
"h": Object {
82+
"generated": false,
83+
"id": "bar",
84+
"type": "id",
85+
"typename": undefined,
86+
},
87+
},
88+
}
89+
`;
90+
91+
exports[
92+
`Cache writeFragment will write some deeply nested data into the store at any id 5`
93+
] = `
94+
Object {
95+
"bar": Object {
96+
"i": 7,
97+
"j": 8,
98+
"k": 9,
99+
},
100+
"foo": Object {
101+
"e": 4,
102+
"f": 5,
103+
"g": 6,
104+
"h": Object {
105+
"generated": false,
106+
"id": "bar",
107+
"type": "id",
108+
"typename": "Bar",
109+
},
110+
},
111+
}
112+
`;
113+
114+
exports[
115+
`Cache writeFragment will write some deeply nested data into the store at any id 6`
116+
] = `
117+
Object {
118+
"bar": Object {
119+
"i": 10,
120+
"j": 11,
121+
"k": 12,
122+
},
123+
"foo": Object {
124+
"e": 4,
125+
"f": 5,
126+
"g": 6,
127+
"h": Object {
128+
"generated": false,
129+
"id": "bar",
130+
"type": "id",
131+
"typename": "Bar",
132+
},
133+
},
134+
}
135+
`;

packages/apollo-cache-inmemory/src/__tests__/__snapshots__/mapCache.ts.snap

+134
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,139 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[
4+
`MapCache Cache writeFragment will write some deeply nested data into the store at any id 1`
5+
] = `
6+
Object {
7+
"bar": Object {
8+
"i": 7,
9+
},
10+
"foo": Object {
11+
"e": 4,
12+
"h": Object {
13+
"generated": false,
14+
"id": "bar",
15+
"type": "id",
16+
"typename": undefined,
17+
},
18+
},
19+
}
20+
`;
21+
22+
exports[
23+
`MapCache Cache writeFragment will write some deeply nested data into the store at any id 2`
24+
] = `
25+
Object {
26+
"bar": Object {
27+
"i": 7,
28+
"j": 8,
29+
"k": 9,
30+
},
31+
"foo": Object {
32+
"e": 4,
33+
"f": 5,
34+
"g": 6,
35+
"h": Object {
36+
"generated": false,
37+
"id": "bar",
38+
"type": "id",
39+
"typename": undefined,
40+
},
41+
},
42+
}
43+
`;
44+
45+
exports[
46+
`MapCache Cache writeFragment will write some deeply nested data into the store at any id 3`
47+
] = `
48+
Object {
49+
"bar": Object {
50+
"i": 10,
51+
"j": 8,
52+
"k": 9,
53+
},
54+
"foo": Object {
55+
"e": 4,
56+
"f": 5,
57+
"g": 6,
58+
"h": Object {
59+
"generated": false,
60+
"id": "bar",
61+
"type": "id",
62+
"typename": undefined,
63+
},
64+
},
65+
}
66+
`;
67+
68+
exports[
69+
`MapCache Cache writeFragment will write some deeply nested data into the store at any id 4`
70+
] = `
71+
Object {
72+
"bar": Object {
73+
"i": 10,
74+
"j": 11,
75+
"k": 12,
76+
},
77+
"foo": Object {
78+
"e": 4,
79+
"f": 5,
80+
"g": 6,
81+
"h": Object {
82+
"generated": false,
83+
"id": "bar",
84+
"type": "id",
85+
"typename": undefined,
86+
},
87+
},
88+
}
89+
`;
90+
91+
exports[
92+
`MapCache Cache writeFragment will write some deeply nested data into the store at any id 5`
93+
] = `
94+
Object {
95+
"bar": Object {
96+
"i": 7,
97+
"j": 8,
98+
"k": 9,
99+
},
100+
"foo": Object {
101+
"e": 4,
102+
"f": 5,
103+
"g": 6,
104+
"h": Object {
105+
"generated": false,
106+
"id": "bar",
107+
"type": "id",
108+
"typename": "Bar",
109+
},
110+
},
111+
}
112+
`;
113+
114+
exports[
115+
`MapCache Cache writeFragment will write some deeply nested data into the store at any id 6`
116+
] = `
117+
Object {
118+
"bar": Object {
119+
"i": 10,
120+
"j": 11,
121+
"k": 12,
122+
},
123+
"foo": Object {
124+
"e": 4,
125+
"f": 5,
126+
"g": 6,
127+
"h": Object {
128+
"generated": false,
129+
"id": "bar",
130+
"type": "id",
131+
"typename": "Bar",
132+
},
133+
},
134+
}
135+
`;
136+
3137
exports[
4138
`MapCache writing to the store throws when trying to write an object without id that was previously queried with id 1`
5139
] = `

0 commit comments

Comments
 (0)