diff --git a/links/gql_dedupe_link/lib/gql_dedupe_link.dart b/links/gql_dedupe_link/lib/gql_dedupe_link.dart index c121d891..e787fcb1 100644 --- a/links/gql_dedupe_link/lib/gql_dedupe_link.dart +++ b/links/gql_dedupe_link/lib/gql_dedupe_link.dart @@ -7,23 +7,32 @@ import "package:gql_link/gql_link.dart"; /// A [Link] to deduplicate [Request]s class DedupeLink extends Link { + final bool Function(Request request) _shouldDedupe; final Map> _inFlight = {}; + static bool _defaultShouldDedupe(Request request) => true; + + DedupeLink({ + bool Function(Request request) shouldDedupe = _defaultShouldDedupe, + }) : _shouldDedupe = shouldDedupe; + @override Stream request( Request request, [ NextLink? forward, ]) { - if (_inFlight.containsKey(request)) { + final shouldDedupe = _shouldDedupe(request); + + if (shouldDedupe && _inFlight.containsKey(request)) { return _inFlight[request]!.split(); } final splitter = StreamSplitter(forward!(request)); - _inFlight[request] = splitter; + if (shouldDedupe) _inFlight[request] = splitter; final closeSplitter = () { - _inFlight.remove(request); + if (shouldDedupe) _inFlight.remove(request); splitter.close(); }; diff --git a/links/gql_dedupe_link/test/gql_dedupe_link_test.dart b/links/gql_dedupe_link/test/gql_dedupe_link_test.dart index 0a1b2bd3..549807c7 100644 --- a/links/gql_dedupe_link/test/gql_dedupe_link_test.dart +++ b/links/gql_dedupe_link/test/gql_dedupe_link_test.dart @@ -1,5 +1,6 @@ import "dart:async"; +import "package:gql/ast.dart"; import "package:gql/language.dart"; import "package:gql_dedupe_link/gql_dedupe_link.dart"; import "package:gql_exec/gql_exec.dart"; @@ -184,6 +185,76 @@ void main() { expect(await return2, result1); }); + test( + "does not dedupe identical queries if shouldDedupe is false for request", + () async { + var count = 0; + final document = parseString( + """ + query withVar(\$i: Int) { + take(i: \$i) + } + """, + ); + + final req1 = Request( + operation: Operation( + document: document, + ), + variables: const {"i": 12}, + ); + + final mockLink = MockLink(); + + when( + mockLink.request(req1, null), + ).thenAnswer((_) { + count++; + return Stream.fromIterable([ + Response( + data: {"a": count}, + response: { + "data": {"a": count} + }, + ) + ]); + }); + + final link = Link.from([ + DedupeLink( + shouldDedupe: (req) => + req.operation.getOperationType() != OperationType.query, + ), + mockLink, + ]); + + final stream1 = link.request(req1); + final stream2 = link.request(req1); + + final return1 = stream1.first; + final return2 = stream2.first; + + verify( + mockLink.request(req1, null), + ).called(2); + expect( + await return1, + Response( + data: const {"a": 1}, + response: const { + "data": {"a": 1} + }, + )); + expect( + await return2, + Response( + data: const {"a": 2}, + response: const { + "data": {"a": 2} + }, + )); + }); + test("does not dedup consequtive queries", () async { final document = parseString( """