@@ -913,6 +913,7 @@ class SelectionVisitor
913913 void visitFragmentSpread (const peg::ast_node& fragmentSpread);
914914 void visitInlineFragment (const peg::ast_node& inlineFragment);
915915
916+ const ResolverContext _resolverContext;
916917 const std::shared_ptr<RequestState>& _state;
917918 const response::Value& _operationDirectives;
918919 const field_path _path;
@@ -930,7 +931,8 @@ class SelectionVisitor
930931SelectionVisitor::SelectionVisitor (const SelectionSetParams& selectionSetParams,
931932 const FragmentMap& fragments, const response::Value& variables,
932933 const TypeNames& typeNames, const ResolverMap& resolvers)
933- : _state(selectionSetParams.state)
934+ : _resolverContext(selectionSetParams.resolverContext)
935+ , _state(selectionSetParams.state)
934936 , _operationDirectives(selectionSetParams.operationDirectives)
935937 , _path(selectionSetParams.errorPath)
936938 , _launch(selectionSetParams.launch)
@@ -1065,6 +1067,7 @@ void SelectionVisitor::visitField(const peg::ast_node& field)
10651067 path.push ({ alias });
10661068
10671069 SelectionSetParams selectionSetParams {
1070+ _resolverContext,
10681071 _state,
10691072 _operationDirectives,
10701073 _fragmentDirectives.top ().fragmentDefinitionDirectives ,
@@ -1445,21 +1448,25 @@ void FragmentDefinitionVisitor::visit(const peg::ast_node& fragmentDefinition)
14451448class OperationDefinitionVisitor
14461449{
14471450public:
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);
14491453
14501454 std::future<response::Value> getValue ();
14511455
14521456 void visit (const std::string& operationType, const peg::ast_node& operationDefinition);
14531457
14541458private:
1459+ const ResolverContext _resolverContext;
14551460 const std::launch _launch;
14561461 std::shared_ptr<OperationData> _params;
14571462 const TypeMap& _operations;
14581463 std::future<response::Value> _result;
14591464};
14601465
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)
14631470 , _params(std::make_shared<OperationData>(
14641471 std::move (state),
14651472 std::move(variables),
@@ -1534,11 +1541,12 @@ void OperationDefinitionVisitor::visit(const std::string& operationType, const p
15341541
15351542 // Keep the params alive until the deferred lambda has executed
15361543 _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)
15381545 {
15391546 // The top level object doesn't come from inside of a fragment, so all of the fragment directives are empty.
15401547 const response::Value emptyFragmentDirectives (response::Type::Map);
15411548 const SelectionSetParams selectionSetParams {
1549+ selectionContext,
15421550 params->state ,
15431551 params->directives ,
15441552 emptyFragmentDirectives,
@@ -1998,14 +2006,20 @@ std::future<response::Value> Request::resolveValidated(std::launch launch, const
19982006 throw schema_exception { { schema_error{ message.str (), { position.line , position.column } } } };
19992007 }
20002008
2009+ const bool isMutation = (operationDefinition.first == strMutation);
2010+
20012011 // http://spec.graphql.org/June2018/#sec-Normal-and-Serial-Execution
2002- if (operationDefinition. first == strMutation )
2012+ if (isMutation )
20032013 {
20042014 // Force mutations to perform serial execution
20052015 launch = std::launch::deferred;
20062016 }
20072017
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));
20092023
20102024 operationVisitor.visit (operationDefinition.first , *operationDefinition.second );
20112025
@@ -2090,6 +2104,45 @@ SubscriptionKey Request::subscribe(SubscriptionParams&& params, SubscriptionCall
20902104 return key;
20912105}
20922106
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+
20932146void Request::unsubscribe (SubscriptionKey key)
20942147{
20952148 auto itrSubscription = _subscriptions.find (key);
@@ -2119,6 +2172,35 @@ void Request::unsubscribe(SubscriptionKey key)
21192172 }
21202173}
21212174
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+
21222204void Request::deliver (const SubscriptionName& name, const std::shared_ptr<Object>& subscriptionObject) const
21232205{
21242206 deliver (std::launch::deferred, name, subscriptionObject);
@@ -2193,6 +2275,7 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, const Su
21932275 std::future<response::Value> result;
21942276 response::Value emptyFragmentDirectives (response::Type::Map);
21952277 const SelectionSetParams selectionSetParams {
2278+ ResolverContext::Subscription,
21962279 registration->data ->state ,
21972280 registration->data ->directives ,
21982281 emptyFragmentDirectives,
0 commit comments