diff --git a/links/gql_dedupe_link/lib/gql_dedupe_link.dart b/links/gql_dedupe_link/lib/gql_dedupe_link.dart index c121d891..da0308e2 100644 --- a/links/gql_dedupe_link/lib/gql_dedupe_link.dart +++ b/links/gql_dedupe_link/lib/gql_dedupe_link.dart @@ -2,28 +2,37 @@ library gql_dedupe_link; import "package:async/async.dart"; +import "package:gql/ast.dart"; import "package:gql_exec/gql_exec.dart"; import "package:gql_link/gql_link.dart"; /// A [Link] to deduplicate [Request]s class DedupeLink extends Link { + final List _nonDedupeTypes; final Map> _inFlight = {}; + DedupeLink({List nonDedupeTypes = const []}) + : _nonDedupeTypes = nonDedupeTypes; + @override Stream request( Request request, [ NextLink? forward, ]) { - if (_inFlight.containsKey(request)) { + final shouldDedupe = !_nonDedupeTypes.contains( + request.operation.getOperationType(), + ); + + 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/pubspec.yaml b/links/gql_dedupe_link/pubspec.yaml index e6e45d6d..de3309d4 100644 --- a/links/gql_dedupe_link/pubspec.yaml +++ b/links/gql_dedupe_link/pubspec.yaml @@ -6,11 +6,11 @@ environment: sdk: '>=2.12.0 <4.0.0' dependencies: async: ^2.5.0 + gql: ^1.0.0 gql_exec: ^1.0.0 gql_link: ^1.0.0 meta: ^1.3.0 dev_dependencies: - gql: ^1.0.0 gql_pedantic: ^1.0.2 mockito: ^5.0.0-nullsafety.7 test: ^1.16.2 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..c4279af3 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,72 @@ void main() { expect(await return2, result1); }); + test("does not dedupe identical queries if of type in nonDedupeTypes", + () 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(nonDedupeTypes: [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( """