@@ -913,6 +913,7 @@ class SelectionVisitor
913
913
void visitFragmentSpread (const peg::ast_node& fragmentSpread);
914
914
void visitInlineFragment (const peg::ast_node& inlineFragment);
915
915
916
+ const ResolverContext _resolverContext;
916
917
const std::shared_ptr<RequestState>& _state;
917
918
const response::Value& _operationDirectives;
918
919
const field_path _path;
@@ -930,7 +931,8 @@ class SelectionVisitor
930
931
SelectionVisitor::SelectionVisitor (const SelectionSetParams& selectionSetParams,
931
932
const FragmentMap& fragments, const response::Value& variables,
932
933
const TypeNames& typeNames, const ResolverMap& resolvers)
933
- : _state(selectionSetParams.state)
934
+ : _resolverContext(selectionSetParams.resolverContext)
935
+ , _state(selectionSetParams.state)
934
936
, _operationDirectives(selectionSetParams.operationDirectives)
935
937
, _path(selectionSetParams.errorPath)
936
938
, _launch(selectionSetParams.launch)
@@ -1065,6 +1067,7 @@ void SelectionVisitor::visitField(const peg::ast_node& field)
1065
1067
path.push ({ alias });
1066
1068
1067
1069
SelectionSetParams selectionSetParams {
1070
+ _resolverContext,
1068
1071
_state,
1069
1072
_operationDirectives,
1070
1073
_fragmentDirectives.top ().fragmentDefinitionDirectives ,
@@ -1445,21 +1448,25 @@ void FragmentDefinitionVisitor::visit(const peg::ast_node& fragmentDefinition)
1445
1448
class OperationDefinitionVisitor
1446
1449
{
1447
1450
public:
1448
- OperationDefinitionVisitor (std::launch launch, std::shared_ptr<RequestState> state, const TypeMap& operations, response::Value&& variables, FragmentMap&& fragments);
1451
+ OperationDefinitionVisitor (ResolverContext resolverContext, std::launch launch, std::shared_ptr<RequestState> state,
1452
+ const TypeMap& operations, response::Value&& variables, FragmentMap&& fragments);
1449
1453
1450
1454
std::future<response::Value> getValue ();
1451
1455
1452
1456
void visit (const std::string& operationType, const peg::ast_node& operationDefinition);
1453
1457
1454
1458
private:
1459
+ const ResolverContext _resolverContext;
1455
1460
const std::launch _launch;
1456
1461
std::shared_ptr<OperationData> _params;
1457
1462
const TypeMap& _operations;
1458
1463
std::future<response::Value> _result;
1459
1464
};
1460
1465
1461
- OperationDefinitionVisitor::OperationDefinitionVisitor (std::launch launch, std::shared_ptr<RequestState> state, const TypeMap& operations, response::Value&& variables, FragmentMap&& fragments)
1462
- : _launch(launch)
1466
+ OperationDefinitionVisitor::OperationDefinitionVisitor (ResolverContext resolverContext, std::launch launch, std::shared_ptr<RequestState> state,
1467
+ const TypeMap& operations, response::Value&& variables, FragmentMap&& fragments)
1468
+ : _resolverContext(resolverContext)
1469
+ , _launch(launch)
1463
1470
, _params(std::make_shared<OperationData>(
1464
1471
std::move (state),
1465
1472
std::move(variables),
@@ -1534,11 +1541,12 @@ void OperationDefinitionVisitor::visit(const std::string& operationType, const p
1534
1541
1535
1542
// Keep the params alive until the deferred lambda has executed
1536
1543
_result = std::async (_launch,
1537
- [selectionLaunch = _launch, params = std::move (_params), operation = itr->second ](const peg::ast_node& selection)
1544
+ [selectionContext = _resolverContext, selectionLaunch = _launch, params = std::move (_params), operation = itr->second ](const peg::ast_node& selection)
1538
1545
{
1539
1546
// The top level object doesn't come from inside of a fragment, so all of the fragment directives are empty.
1540
1547
const response::Value emptyFragmentDirectives (response::Type::Map);
1541
1548
const SelectionSetParams selectionSetParams {
1549
+ selectionContext,
1542
1550
params->state ,
1543
1551
params->directives ,
1544
1552
emptyFragmentDirectives,
@@ -1998,14 +2006,20 @@ std::future<response::Value> Request::resolveValidated(std::launch launch, const
1998
2006
throw schema_exception { { schema_error{ message.str (), { position.line , position.column } } } };
1999
2007
}
2000
2008
2009
+ const bool isMutation = (operationDefinition.first == strMutation);
2010
+
2001
2011
// http://spec.graphql.org/June2018/#sec-Normal-and-Serial-Execution
2002
- if (operationDefinition. first == strMutation )
2012
+ if (isMutation )
2003
2013
{
2004
2014
// Force mutations to perform serial execution
2005
2015
launch = std::launch::deferred;
2006
2016
}
2007
2017
2008
- OperationDefinitionVisitor operationVisitor (launch, state, _operations, std::move (variables), std::move (fragments));
2018
+ const auto resolverContext = isMutation
2019
+ ? ResolverContext::Mutation
2020
+ : ResolverContext::Query;
2021
+
2022
+ OperationDefinitionVisitor operationVisitor (resolverContext, launch, state, _operations, std::move (variables), std::move (fragments));
2009
2023
2010
2024
operationVisitor.visit (operationDefinition.first , *operationDefinition.second );
2011
2025
@@ -2090,6 +2104,45 @@ SubscriptionKey Request::subscribe(SubscriptionParams&& params, SubscriptionCall
2090
2104
return key;
2091
2105
}
2092
2106
2107
+ std::future<SubscriptionKey> Request::subscribe (std::launch launch, SubscriptionParams&& params, SubscriptionCallback&& callback)
2108
+ {
2109
+ return std::async (launch, [spThis = shared_from_this (), launch](SubscriptionParams&& paramsFuture, SubscriptionCallback&& callbackFuture)
2110
+ {
2111
+ const auto key = spThis->subscribe (std::move (paramsFuture), std::move (callbackFuture));
2112
+ const auto itrOperation = spThis->_operations .find (std::string { strSubscription });
2113
+
2114
+ if (itrOperation != spThis->_operations .cend ())
2115
+ {
2116
+ const auto & operation = itrOperation->second ;
2117
+ const auto & registration = spThis->_subscriptions .at (key);
2118
+ response::Value emptyFragmentDirectives (response::Type::Map);
2119
+ const SelectionSetParams selectionSetParams {
2120
+ ResolverContext::NotifySubscribe,
2121
+ registration->data ->state ,
2122
+ registration->data ->directives ,
2123
+ emptyFragmentDirectives,
2124
+ emptyFragmentDirectives,
2125
+ emptyFragmentDirectives,
2126
+ {},
2127
+ launch,
2128
+ };
2129
+
2130
+ try
2131
+ {
2132
+ operation->resolve (selectionSetParams, registration->selection , registration->data ->fragments , registration->data ->variables ).get ();
2133
+ }
2134
+ catch (const std::exception& ex)
2135
+ {
2136
+ // Rethrow the exception, but don't leave it subscribed if the resolver failed.
2137
+ spThis->unsubscribe (key);
2138
+ throw ex;
2139
+ }
2140
+ }
2141
+
2142
+ return key;
2143
+ }, std::move (params), std::move (callback));
2144
+ }
2145
+
2093
2146
void Request::unsubscribe (SubscriptionKey key)
2094
2147
{
2095
2148
auto itrSubscription = _subscriptions.find (key);
@@ -2119,6 +2172,35 @@ void Request::unsubscribe(SubscriptionKey key)
2119
2172
}
2120
2173
}
2121
2174
2175
+ std::future<void > Request::unsubscribe (std::launch launch, SubscriptionKey key)
2176
+ {
2177
+ return std::async (launch, [spThis = shared_from_this (), launch, key]()
2178
+ {
2179
+ const auto itrOperation = spThis->_operations .find (std::string { strSubscription });
2180
+
2181
+ if (itrOperation != spThis->_operations .cend ())
2182
+ {
2183
+ const auto & operation = itrOperation->second ;
2184
+ const auto & registration = spThis->_subscriptions .at (key);
2185
+ response::Value emptyFragmentDirectives (response::Type::Map);
2186
+ const SelectionSetParams selectionSetParams {
2187
+ ResolverContext::NotifyUnsubscribe,
2188
+ registration->data ->state ,
2189
+ registration->data ->directives ,
2190
+ emptyFragmentDirectives,
2191
+ emptyFragmentDirectives,
2192
+ emptyFragmentDirectives,
2193
+ {},
2194
+ launch,
2195
+ };
2196
+
2197
+ operation->resolve (selectionSetParams, registration->selection , registration->data ->fragments , registration->data ->variables ).get ();
2198
+ }
2199
+
2200
+ spThis->unsubscribe (key);
2201
+ });
2202
+ }
2203
+
2122
2204
void Request::deliver (const SubscriptionName& name, const std::shared_ptr<Object>& subscriptionObject) const
2123
2205
{
2124
2206
deliver (std::launch::deferred, name, subscriptionObject);
@@ -2193,6 +2275,7 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, const Su
2193
2275
std::future<response::Value> result;
2194
2276
response::Value emptyFragmentDirectives (response::Type::Map);
2195
2277
const SelectionSetParams selectionSetParams {
2278
+ ResolverContext::Subscription,
2196
2279
registration->data ->state ,
2197
2280
registration->data ->directives ,
2198
2281
emptyFragmentDirectives,
0 commit comments