-
-
Notifications
You must be signed in to change notification settings - Fork 630
/
Copy pathmutation.dart
132 lines (113 loc) · 3.4 KB
/
mutation.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import 'package:flutter/widgets.dart';
import 'package:graphql/client.dart';
import 'package:graphql_flutter/src/widgets/graphql_provider.dart';
typedef RunMutation = MultiSourceResult Function(
Map<String, dynamic> variables, {
Object optimisticResult,
});
typedef MutationBuilder = Widget Function(
RunMutation runMutation,
QueryResult result,
);
/// Builds a [Mutation] widget based on the a given set of [MutationOptions]
/// that streams [QueryResult]s into the [QueryBuilder].
class Mutation extends StatefulWidget {
const Mutation({
final Key key,
@required this.options,
@required this.builder,
}) : super(key: key);
final MutationOptions options;
final MutationBuilder builder;
@override
MutationState createState() => MutationState();
}
class MutationState extends State<Mutation> {
GraphQLClient client;
ObservableQuery observableQuery;
WatchQueryOptions __cachedOptions;
WatchQueryOptions get _providedOptions {
final _options = WatchQueryOptions(
document: widget.options.document,
variables: widget.options.variables,
fetchPolicy: widget.options.fetchPolicy,
errorPolicy: widget.options.errorPolicy,
fetchResults: false,
context: widget.options.context,
);
__cachedOptions ??= _options;
return _options;
}
/// sets new options, returning true if they didn't equal the old
bool _setNewOptions() {
final _cached = __cachedOptions;
final _new = _providedOptions;
if (_cached == null || !_new.equal(_cached)) {
__cachedOptions = _new;
return true;
}
return false;
}
// TODO is it possible to extract shared logic into mixin
void _initQuery() {
observableQuery?.close();
observableQuery = client.watchQuery(_providedOptions.copy());
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
final GraphQLClient client = GraphQLProvider.of(context).value;
assert(client != null);
if (client != this.client) {
this.client = client;
_initQuery();
}
}
@override
void didUpdateWidget(Mutation oldWidget) {
super.didUpdateWidget(oldWidget);
// TODO @micimize - investigate why/if this was causing issues
if (_setNewOptions()) {
_initQuery();
}
}
/// Run the mutation with the given `variables` and `optimisticResult`,
/// returning a [MultiSourceResult] for handling both the eager and network results
MultiSourceResult runMutation(
Map<String, dynamic> variables, {
Object optimisticResult,
}) {
final mutationCallbacks = MutationCallbackHandler(
cache: client.cache,
queryId: observableQuery.queryId,
options: widget.options,
);
return (observableQuery
..variables = variables
..options.optimisticResult = optimisticResult
..onData(mutationCallbacks.callbacks) // add callbacks to observable
)
.fetchResults();
}
@override
void dispose() {
observableQuery?.close(force: false);
super.dispose();
}
@override
Widget build(BuildContext context) {
return StreamBuilder<QueryResult>(
initialData: observableQuery?.latestResult ?? QueryResult.empty(),
stream: observableQuery?.stream,
builder: (
BuildContext buildContext,
AsyncSnapshot<QueryResult> snapshot,
) {
return widget.builder(
runMutation,
snapshot.data,
);
},
);
}
}