Skip to content

Commit 4d32e16

Browse files
committed
listen to cache changes when using FetchPolicy.NetworkOnly
1 parent 7f6a63c commit 4d32e16

File tree

54 files changed

+1814
-171
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1814
-171
lines changed

packages/ferry/lib/src/fetch_policy_typed_link.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ class FetchPolicyTypedLink extends TypedLink {
7272
.request(operationRequest)
7373
.doOnData(_removeOptimisticPatch)
7474
.doOnData(_writeToCache)
75-
.doOnCancel(() => cache.removeOptimisticPatch(operationRequest));
75+
.doOnCancel(() => cache.removeOptimisticPatch(operationRequest))
76+
.concatWith([_cacheTypedLink.request(operationRequest).skip(1)]);
7677
case FetchPolicy.CacheOnly:
7778
return _cacheTypedLink.request(operationRequest);
7879
case FetchPolicy.CacheFirst:

packages/ferry/test/typed_links/fetch_policy_typed_link_test.dart

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:rxdart/rxdart.dart';
1212
import 'package:ferry/src/fetch_policy_typed_link.dart';
1313
import 'package:ferry_test_graphql2/queries/__generated__/human_with_args.req.gql.dart';
1414
import 'package:ferry_test_graphql2/queries/__generated__/human_with_args.data.gql.dart';
15+
import 'package:ferry_test_graphql2/fragments/__generated__/human_fragment.req.gql.dart';
1516

1617
import './fetch_policy_typed_link_test.mocks.dart';
1718

@@ -50,10 +51,13 @@ void main() {
5051
late StreamController<OperationRequest> requestController;
5152
late TypedLink typedLink;
5253
late Cache cache;
54+
late FetchPolicyTypedLink fetchPolicyTypedLink;
5355

5456
setUp(() {
5557
requestController = StreamController<OperationRequest>();
5658
cache = Cache();
59+
fetchPolicyTypedLink = FetchPolicyTypedLink(link: mockLink, cache: cache);
60+
5761
typedLink = TypedLink.from([
5862
TypedLink.function(
5963
<TData, TVars>(req, [forward]) => requestController.stream
@@ -62,7 +66,7 @@ void main() {
6266
(req) => forward!(req),
6367
),
6468
),
65-
FetchPolicyTypedLink(link: mockLink, cache: cache),
69+
fetchPolicyTypedLink,
6670
]);
6771
});
6872

@@ -164,6 +168,54 @@ void main() {
164168
]),
165169
);
166170
});
171+
172+
test('emit new event when cache changes', () async {
173+
final modifiedName = 'modified name';
174+
final modifiedData = GHumanWithArgsData(
175+
(b) => b
176+
..human.id = 'steve'
177+
..human.name = modifiedName
178+
..human.height = 1.88,
179+
);
180+
181+
when(mockLink.request(any, any)).thenAnswer((_) => Stream.fromIterable([
182+
Response(data: data.toJson(), response: {}),
183+
]));
184+
185+
final stream = fetchPolicyTypedLink.request(req);
186+
187+
unawaited(expectLater(
188+
stream,
189+
emitsInOrder([
190+
// Data emitted from making a request.
191+
equals(
192+
OperationResponse(
193+
operationRequest: req,
194+
dataSource: DataSource.Link,
195+
data: data,
196+
),
197+
),
198+
// Data emitted because of changes in cache [writeFragment].
199+
equals(
200+
OperationResponse(
201+
operationRequest: req,
202+
dataSource: DataSource.Cache,
203+
data: modifiedData,
204+
),
205+
),
206+
]),
207+
));
208+
209+
await pumpEventQueue();
210+
211+
final fragmentRequest = GHumanFragmentReq(
212+
(b) => b.idFields = {'id': 'steve'},
213+
);
214+
final currentCacheData = cache.readFragment(fragmentRequest);
215+
final modifiedCacheData =
216+
currentCacheData!.rebuild((b) => b.name = modifiedName);
217+
cache.writeFragment(fragmentRequest, modifiedCacheData);
218+
});
167219
});
168220

169221
group('.NetworkOnly', () {
@@ -185,6 +237,54 @@ void main() {
185237
final second = await queue.next;
186238
expect(second.dataSource, equals(DataSource.Link));
187239
});
240+
241+
test('emit new event when cache changes', () async {
242+
final modifiedName = 'modified name';
243+
final modifiedData = GHumanWithArgsData(
244+
(b) => b
245+
..human.id = 'steve'
246+
..human.name = modifiedName
247+
..human.height = 1.88,
248+
);
249+
250+
when(mockLink.request(any, any)).thenAnswer((_) => Stream.fromIterable([
251+
Response(data: data.toJson(), response: {}),
252+
]));
253+
254+
final stream = fetchPolicyTypedLink.request(req);
255+
256+
unawaited(expectLater(
257+
stream,
258+
emitsInOrder([
259+
// Data emitted from making a request.
260+
equals(
261+
OperationResponse(
262+
operationRequest: req,
263+
dataSource: DataSource.Link,
264+
data: data,
265+
),
266+
),
267+
// Data emitted because of changes in cache [writeFragment].
268+
equals(
269+
OperationResponse(
270+
operationRequest: req,
271+
dataSource: DataSource.Cache,
272+
data: modifiedData,
273+
),
274+
),
275+
]),
276+
));
277+
278+
await pumpEventQueue();
279+
280+
final fragmentRequest = GHumanFragmentReq(
281+
(b) => b.idFields = {'id': 'steve'},
282+
);
283+
final currentCacheData = cache.readFragment(fragmentRequest);
284+
final modifiedCacheData =
285+
currentCacheData!.rebuild((b) => b.name = modifiedName);
286+
cache.writeFragment(fragmentRequest, modifiedCacheData);
287+
});
188288
});
189289

190290
group('.CacheOnly', () {
@@ -209,6 +309,56 @@ void main() {
209309
expect(response.dataSource, equals(DataSource.Cache));
210310
expect(response.data, equals(data));
211311
});
312+
313+
test('emit new event when cache changes', () async {
314+
final modifiedName = 'modified name';
315+
final modifiedData = GHumanWithArgsData(
316+
(b) => b
317+
..human.id = 'steve'
318+
..human.name = modifiedName
319+
..human.height = 1.88,
320+
);
321+
322+
when(mockLink.request(any, any)).thenAnswer((_) => Stream.fromIterable([
323+
Response(data: data.toJson(), response: {}),
324+
]));
325+
326+
final stream = fetchPolicyTypedLink.request(req);
327+
// Inistal cache data.
328+
cache.writeQuery(req, data);
329+
330+
unawaited(expectLater(
331+
stream,
332+
emitsInOrder([
333+
// Initial data emitted from cache.
334+
equals(
335+
OperationResponse(
336+
operationRequest: req,
337+
dataSource: DataSource.Cache,
338+
data: data,
339+
),
340+
),
341+
// Data emitted because of changes in cache [writeFragment].
342+
equals(
343+
OperationResponse(
344+
operationRequest: req,
345+
dataSource: DataSource.Cache,
346+
data: modifiedData,
347+
),
348+
),
349+
]),
350+
));
351+
352+
await pumpEventQueue();
353+
354+
final fragmentRequest = GHumanFragmentReq(
355+
(b) => b.idFields = {'id': 'steve'},
356+
);
357+
final currentCacheData = cache.readFragment(fragmentRequest);
358+
final modifiedCacheData =
359+
currentCacheData!.rebuild((b) => b.name = modifiedName);
360+
cache.writeFragment(fragmentRequest, modifiedCacheData);
361+
});
212362
});
213363

214364
group('.NoCache', () {

packages/ferry_test_graphql2/lib/fragments/__generated__/human_fragment.ast.gql.dart

Lines changed: 78 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)