diff --git a/packages/graphql/lib/src/core/query_result.dart b/packages/graphql/lib/src/core/query_result.dart index 79fe9677b..5b5b5b38f 100644 --- a/packages/graphql/lib/src/core/query_result.dart +++ b/packages/graphql/lib/src/core/query_result.dart @@ -43,12 +43,14 @@ final _eagerSources = { class QueryResult { @protected QueryResult.internal({ - this.data, + Map? data, this.exception, this.context = const Context(), required this.parserFn, required this.source, - }) : timestamp = DateTime.now(); + }) : timestamp = DateTime.now() { + _data = data; + } factory QueryResult({ required BaseOptions options, @@ -99,7 +101,17 @@ class QueryResult { QueryResultSource? source; /// Response data - Map? data; + Map? get data { + return _data; + } + + set data(Map? data) { + _data = data; + _cachedParsedData = null; + } + + Map? _data; + TParsed? _cachedParsedData; /// Response context. Defaults to an empty `Context()` Context context; @@ -137,11 +149,15 @@ class QueryResult { TParsed? get parsedData { final data = this.data; final parserFn = this.parserFn; + final cachedParsedData = _cachedParsedData; if (data == null) { return null; } - return parserFn(data); + if (cachedParsedData != null) { + return cachedParsedData; + } + return _cachedParsedData = parserFn(data); } @override diff --git a/packages/graphql/test/query_result_test.dart b/packages/graphql/test/query_result_test.dart new file mode 100644 index 000000000..a6064e074 --- /dev/null +++ b/packages/graphql/test/query_result_test.dart @@ -0,0 +1,76 @@ +import 'package:gql/language.dart'; +import 'package:graphql/client.dart'; +import 'package:test/test.dart'; + +void main() { + group('Query result', () { + test('data parsing should work with null data', () { + int runTimes = 0; + final result = QueryResult( + options: QueryOptions( + document: parseString('query { bar }'), + parserFn: (data) { + runTimes++; + return data['bar'] as String?; + }, + ), + source: QueryResultSource.network, + data: null, + ); + expect(result.parsedData, equals(null)); + expect(runTimes, equals(0)); + }); + test('data parsing should work with data', () { + int runTimes = 0; + final bar = "Bar"; + final result = QueryResult( + options: QueryOptions( + document: parseString('query { bar }'), + parserFn: (data) { + runTimes++; + return data['bar'] as String?; + }, + ), + source: QueryResultSource.network, + data: {"bar": bar}, + ); + expect(result.parsedData, equals(bar)); + expect(result.parsedData, equals(bar)); + expect(runTimes, equals(1)); + }); + test('data parsing should work with data', () { + final bar = "Bar"; + final result = QueryResult( + options: QueryOptions( + document: parseString('query { bar }'), + parserFn: (data) { + return data['bar'] as String?; + }, + ), + source: QueryResultSource.network, + data: {"bar": bar}, + ); + expect(result.data, equals({"bar": bar})); + }); + test('updating data should clear parsed data', () { + int runTimes = 0; + final bar = "Bar"; + final result = QueryResult( + options: QueryOptions( + document: parseString('query { bar }'), + parserFn: (data) { + runTimes++; + return data['bar'] as String?; + }, + ), + source: QueryResultSource.network, + data: {"bar": bar}, + ); + expect(result.parsedData, equals(bar)); + expect(runTimes, equals(1)); + result.data = {"bar": bar}; + expect(result.parsedData, equals(bar)); + expect(runTimes, equals(2)); + }); + }); +}