Skip to content

Commit a9c7101

Browse files
committed
Add subscription filtering on field directives
1 parent b7172d5 commit a9c7101

File tree

2 files changed

+105
-28
lines changed

2 files changed

+105
-28
lines changed

include/graphqlservice/GraphQLService.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -848,14 +848,16 @@ using SubscriptionName = std::string;
848848
// Registration information for subscription, cached in the Request::subscribe call.
849849
struct SubscriptionData : std::enable_shared_from_this<SubscriptionData>
850850
{
851-
explicit SubscriptionData(std::shared_ptr<OperationData>&& data, SubscriptionName&& field, response::Value&& arguments,
851+
explicit SubscriptionData(std::shared_ptr<OperationData>&& data, SubscriptionName&& field,
852+
response::Value&& arguments, response::Value&& fieldDirectives,
852853
peg::ast&& query, std::string&& operationName, SubscriptionCallback&& callback,
853854
const peg::ast_node& selection);
854855

855856
std::shared_ptr<OperationData> data;
856857

857858
SubscriptionName field;
858859
response::Value arguments;
860+
response::Value fieldDirectives;
859861
peg::ast query;
860862
std::string operationName;
861863
SubscriptionCallback callback;
@@ -887,11 +889,15 @@ class Request : public std::enable_shared_from_this<Request>
887889

888890
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, const std::shared_ptr<Object>& subscriptionObject) const;
889891
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, const SubscriptionArguments& arguments, const std::shared_ptr<Object>& subscriptionObject) const;
890-
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, const SubscriptionFilterCallback& apply, const std::shared_ptr<Object>& subscriptionObject) const;
892+
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, const SubscriptionArguments& arguments, const SubscriptionArguments& directives, const std::shared_ptr<Object>& subscriptionObject) const;
893+
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, const SubscriptionFilterCallback& applyArguments, const std::shared_ptr<Object>& subscriptionObject) const;
894+
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, const SubscriptionFilterCallback& applyArguments, const SubscriptionFilterCallback& applyDirectives, const std::shared_ptr<Object>& subscriptionObject) const;
891895

892896
GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, const std::shared_ptr<Object>& subscriptionObject) const;
893897
GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, const SubscriptionArguments& arguments, const std::shared_ptr<Object>& subscriptionObject) const;
894-
GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, const SubscriptionFilterCallback& apply, const std::shared_ptr<Object>& subscriptionObject) const;
898+
GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, const SubscriptionArguments& arguments, const SubscriptionArguments& directives, const std::shared_ptr<Object>& subscriptionObject) const;
899+
GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, const SubscriptionFilterCallback& applyArguments, const std::shared_ptr<Object>& subscriptionObject) const;
900+
GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, const SubscriptionFilterCallback& applyArguments, const SubscriptionFilterCallback& applyDirectives, const std::shared_ptr<Object>& subscriptionObject) const;
895901

896902
[[deprecated("Use the Request::resolve overload which takes a peg::ast reference instead.")]]
897903
GRAPHQLSERVICE_EXPORT std::future<response::Value> resolve(const std::shared_ptr<RequestState>& state, const peg::ast_node& root, const std::string& operationName, response::Value&& variables) const;

src/GraphQLService.cpp

Lines changed: 96 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,12 +1530,14 @@ void OperationDefinitionVisitor::visit(const std::string& operationType, const p
15301530
}, std::cref(*operationDefinition.children.back()));
15311531
}
15321532

1533-
SubscriptionData::SubscriptionData(std::shared_ptr<OperationData>&& data, SubscriptionName&& field, response::Value&& arguments,
1533+
SubscriptionData::SubscriptionData(std::shared_ptr<OperationData>&& data, SubscriptionName&& field,
1534+
response::Value&& arguments, response::Value&& fieldDirectives,
15341535
peg::ast&& query, std::string&& operationName, SubscriptionCallback&& callback,
15351536
const peg::ast_node& selection)
15361537
: data(std::move(data))
15371538
, field(std::move(field))
15381539
, arguments(std::move(arguments))
1540+
, fieldDirectives(std::move(fieldDirectives))
15391541
, query(std::move(query))
15401542
, operationName(std::move(operationName))
15411543
, callback(std::move(callback))
@@ -1566,6 +1568,7 @@ class SubscriptionDefinitionVisitor
15661568
const std::shared_ptr<Object>& _subscriptionObject;
15671569
SubscriptionName _field;
15681570
response::Value _arguments;
1571+
response::Value _fieldDirectives;
15691572
std::shared_ptr<SubscriptionData> _result;
15701573
};
15711574

@@ -1630,6 +1633,7 @@ void SubscriptionDefinitionVisitor::visit(const peg::ast_node& operationDefiniti
16301633
std::move(_fragments)),
16311634
std::move(_field),
16321635
std::move(_arguments),
1636+
std::move(_fieldDirectives),
16331637
std::move(_params.query),
16341638
std::move(_params.operationName),
16351639
std::move(_callback),
@@ -1670,6 +1674,8 @@ void SubscriptionDefinitionVisitor::visitField(const peg::ast_node& field)
16701674
return;
16711675
}
16721676

1677+
_fieldDirectives = directiveVisitor.getDirectives();
1678+
16731679
response::Value arguments(response::Type::Map);
16741680

16751681
peg::on_first_child<peg::arguments>(field,
@@ -2176,35 +2182,76 @@ void Request::deliver(const SubscriptionName& name, const std::shared_ptr<Object
21762182
deliver(std::launch::deferred, name, subscriptionObject);
21772183
}
21782184

2179-
void Request::deliver(std::launch launch, const SubscriptionName& name, const std::shared_ptr<Object>& subscriptionObject) const
2185+
void Request::deliver(const SubscriptionName& name, const SubscriptionArguments& arguments, const std::shared_ptr<Object>& subscriptionObject) const
21802186
{
2181-
deliver(launch, name, SubscriptionArguments {}, subscriptionObject);
2187+
deliver(std::launch::deferred, name, arguments, subscriptionObject);
21822188
}
21832189

2184-
void Request::deliver(const SubscriptionName& name, const SubscriptionArguments& arguments, const std::shared_ptr<Object>& subscriptionObject) const
2190+
void Request::deliver(const SubscriptionName& name, const SubscriptionArguments& arguments,
2191+
const SubscriptionArguments& directives, const std::shared_ptr<Object>& subscriptionObject) const
21852192
{
2186-
deliver(std::launch::deferred, name, arguments, subscriptionObject);
2193+
deliver(std::launch::deferred, name, arguments, directives, subscriptionObject);
2194+
}
2195+
2196+
void Request::deliver(const SubscriptionName& name, const SubscriptionFilterCallback& applyArguments,
2197+
const std::shared_ptr<Object>& subscriptionObject) const
2198+
{
2199+
deliver(std::launch::deferred, name, applyArguments, subscriptionObject);
2200+
}
2201+
2202+
void Request::deliver(const SubscriptionName& name, const SubscriptionFilterCallback& applyArguments,
2203+
const SubscriptionFilterCallback& applyDirectives, const std::shared_ptr<Object>& subscriptionObject) const
2204+
{
2205+
deliver(std::launch::deferred, name, applyArguments, applyDirectives, subscriptionObject);
2206+
}
2207+
2208+
void Request::deliver(std::launch launch, const SubscriptionName& name,
2209+
const std::shared_ptr<Object>& subscriptionObject) const
2210+
{
2211+
deliver(launch, name, SubscriptionArguments {}, SubscriptionArguments {}, subscriptionObject);
21872212
}
21882213

21892214
void Request::deliver(std::launch launch, const SubscriptionName& name, const SubscriptionArguments& arguments, const std::shared_ptr<Object>& subscriptionObject) const
21902215
{
2191-
SubscriptionFilterCallback exactMatch = [&arguments](response::MapType::const_reference required) noexcept -> bool
2192-
{
2216+
deliver(launch, name, arguments, SubscriptionArguments {}, subscriptionObject);
2217+
}
2218+
2219+
void Request::deliver(std::launch launch, const SubscriptionName& name,
2220+
const SubscriptionArguments& arguments, const SubscriptionArguments& directives,
2221+
const std::shared_ptr<Object>& subscriptionObject) const
2222+
{
2223+
SubscriptionFilterCallback argumentsMatch =
2224+
[&arguments](response::MapType::const_reference required) noexcept -> bool {
21932225
auto itrArgument = arguments.find(required.first);
21942226

2195-
return (itrArgument != arguments.cend()
2196-
&& itrArgument->second == required.second);
2227+
return (itrArgument != arguments.cend() && itrArgument->second == required.second);
21972228
};
21982229

2199-
deliver(launch, name, exactMatch, subscriptionObject);
2230+
SubscriptionFilterCallback directivesMatch =
2231+
[&directives](response::MapType::const_reference required) noexcept -> bool {
2232+
auto itrDirective = directives.find(required.first);
2233+
2234+
return (itrDirective != directives.cend() && itrDirective->second == required.second);
2235+
};
2236+
2237+
deliver(launch, name, argumentsMatch, directivesMatch, subscriptionObject);
22002238
}
22012239

2202-
void Request::deliver(const SubscriptionName& name, const SubscriptionFilterCallback& apply, const std::shared_ptr<Object>& subscriptionObject) const
2240+
void Request::deliver(std::launch launch, const SubscriptionName& name, const SubscriptionFilterCallback& applyArguments, const std::shared_ptr<Object>& subscriptionObject) const
22032241
{
2204-
deliver(std::launch::deferred, name, apply, subscriptionObject);
2242+
deliver(
2243+
launch,
2244+
name,
2245+
applyArguments,
2246+
[](response::MapType::const_reference) noexcept {
2247+
return true;
2248+
},
2249+
subscriptionObject);
22052250
}
22062251

2207-
void Request::deliver(std::launch launch, const SubscriptionName& name, const SubscriptionFilterCallback& apply, const std::shared_ptr<Object>& subscriptionObject) const
2252+
void Request::deliver(std::launch launch, const SubscriptionName& name,
2253+
const SubscriptionFilterCallback& applyArguments, const SubscriptionFilterCallback& applyDirectives,
2254+
const std::shared_ptr<Object>& subscriptionObject) const
22082255
{
22092256
const auto& optionalOrDefaultSubscription = subscriptionObject
22102257
? subscriptionObject
@@ -2230,7 +2277,7 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, const Su
22302277
// in this event, don't deliver the event to this subscription
22312278
for (const auto& required : subscriptionArguments)
22322279
{
2233-
if (!apply(required))
2280+
if (!applyArguments(required))
22342281
{
22352282
matchedArguments = false;
22362283
break;
@@ -2242,6 +2289,25 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, const Su
22422289
continue;
22432290
}
22442291

2292+
// If the field in this subscription had field directives that did not match what was
2293+
// provided in this event, don't deliver the event to this subscription
2294+
const auto& subscriptionFieldDirectives = registration->fieldDirectives;
2295+
bool matchedFieldDirectives = true;
2296+
2297+
for (const auto& required : subscriptionFieldDirectives)
2298+
{
2299+
if (!applyDirectives(required))
2300+
{
2301+
matchedFieldDirectives = false;
2302+
break;
2303+
}
2304+
}
2305+
2306+
if (!matchedFieldDirectives)
2307+
{
2308+
continue;
2309+
}
2310+
22452311
std::future<response::Value> result;
22462312
response::Value emptyFragmentDirectives(response::Type::Map);
22472313
const SelectionSetParams selectionSetParams {
@@ -2257,13 +2323,17 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, const Su
22572323

22582324
try
22592325
{
2260-
result = std::async(launch,
2261-
[registration](std::future<response::Value> document)
2262-
{
2263-
return document.get();
2264-
}, optionalOrDefaultSubscription->resolve(selectionSetParams, registration->selection, registration->data->fragments, registration->data->variables));
2326+
result = std::async(
2327+
launch,
2328+
[registration](std::future<response::Value> document) {
2329+
return document.get();
2330+
},
2331+
optionalOrDefaultSubscription->resolve(selectionSetParams,
2332+
registration->selection,
2333+
registration->data->fragments,
2334+
registration->data->variables));
22652335
}
2266-
catch (schema_exception & ex)
2336+
catch (schema_exception& ex)
22672337
{
22682338
std::promise<response::Value> promise;
22692339
response::Value document(response::Type::Map);
@@ -2275,11 +2345,12 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, const Su
22752345
result = promise.get_future();
22762346
}
22772347

2278-
callbacks.push(std::async(launch,
2279-
[registration](std::future<response::Value> document)
2280-
{
2281-
registration->callback(std::move(document));
2282-
}, std::move(result)));
2348+
callbacks.push(std::async(
2349+
launch,
2350+
[registration](std::future<response::Value> document) {
2351+
registration->callback(std::move(document));
2352+
},
2353+
std::move(result)));
22832354
}
22842355

22852356
while (!callbacks.empty())

0 commit comments

Comments
 (0)