Skip to content

Commit ee943ac

Browse files
committed
Preserve error location and path when visiting awaitable resolvers
1 parent 81a3854 commit ee943ac

File tree

1 file changed

+50
-33
lines changed

1 file changed

+50
-33
lines changed

src/GraphQLService.cpp

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,15 @@ class SelectionVisitor
869869

870870
void visit(const peg::ast_node& selection);
871871

872-
std::vector<std::pair<std::string_view, AwaitableResolver>> getValues();
872+
struct VisitorValue
873+
{
874+
std::string_view name;
875+
std::optional<schema_location> location;
876+
std::optional<error_path> path;
877+
AwaitableResolver result;
878+
};
879+
880+
std::vector<VisitorValue> getValues();
873881

874882
private:
875883
void visitField(const peg::ast_node& field);
@@ -890,7 +898,7 @@ class SelectionVisitor
890898
std::shared_ptr<FragmentSpreadDirectiveStack> _fragmentSpreadDirectives;
891899
std::shared_ptr<FragmentSpreadDirectiveStack> _inlineFragmentDirectives;
892900
internal::string_view_set _names;
893-
std::vector<std::pair<std::string_view, AwaitableResolver>> _values;
901+
std::vector<VisitorValue> _values;
894902
};
895903

896904
SelectionVisitor::SelectionVisitor(const SelectionSetParams& selectionSetParams,
@@ -924,7 +932,7 @@ SelectionVisitor::SelectionVisitor(const SelectionSetParams& selectionSetParams,
924932
_values.reserve(count);
925933
}
926934

927-
std::vector<std::pair<std::string_view, AwaitableResolver>> SelectionVisitor::getValues()
935+
std::vector<SelectionVisitor::VisitorValue> SelectionVisitor::getValues()
928936
{
929937
auto values = std::move(_values);
930938

@@ -989,7 +997,7 @@ void SelectionVisitor::visitField(const peg::ast_node& field)
989997
{ position.line, position.column },
990998
buildErrorPath(_path ? std::make_optional(_path->get()) : std::nullopt) } } }));
991999

992-
_values.push_back({ alias, promise.get_future() });
1000+
_values.push_back({ alias, std::nullopt, std::nullopt, promise.get_future() });
9931001
return;
9941002
}
9951003

@@ -1033,6 +1041,7 @@ void SelectionVisitor::visitField(const peg::ast_node& field)
10331041
std::make_optional(field_path { _path, path_segment { alias } }),
10341042
_launch,
10351043
};
1044+
const auto position = field.begin();
10361045

10371046
try
10381047
{
@@ -1045,12 +1054,14 @@ void SelectionVisitor::visitField(const peg::ast_node& field)
10451054
_fragments,
10461055
_variables));
10471056

1048-
_values.push_back({ alias, std::move(result) });
1057+
_values.push_back({ alias,
1058+
std::make_optional<schema_location>({ position.line, position.column }),
1059+
std::make_optional(buildErrorPath(selectionSetParams.errorPath)),
1060+
std::move(result) });
10491061
}
10501062
catch (schema_exception& scx)
10511063
{
10521064
std::promise<ResolverResult> promise;
1053-
auto position = field.begin();
10541065
auto messages = scx.getStructuredErrors();
10551066

10561067
for (auto& message : messages)
@@ -1068,12 +1079,11 @@ void SelectionVisitor::visitField(const peg::ast_node& field)
10681079

10691080
promise.set_exception(std::make_exception_ptr(schema_exception { std::move(messages) }));
10701081

1071-
_values.push_back({ alias, promise.get_future() });
1082+
_values.push_back({ alias, std::nullopt, std::nullopt, promise.get_future() });
10721083
}
10731084
catch (const std::exception& ex)
10741085
{
10751086
std::promise<ResolverResult> promise;
1076-
auto position = field.begin();
10771087
std::ostringstream message;
10781088

10791089
message << "Field error name: " << alias << " unknown error: " << ex.what();
@@ -1083,7 +1093,7 @@ void SelectionVisitor::visitField(const peg::ast_node& field)
10831093
{ position.line, position.column },
10841094
buildErrorPath(selectionSetParams.errorPath) } } }));
10851095

1086-
_values.push_back({ alias, promise.get_future() });
1096+
_values.push_back({ alias, std::nullopt, std::nullopt, promise.get_future() });
10871097
}
10881098
}
10891099

@@ -1222,21 +1232,23 @@ AwaitableResolver Object::resolve(const SelectionSetParams& selectionSetParams,
12221232

12231233
for (auto& child : children)
12241234
{
1225-
auto name = child.first;
1226-
12271235
try
12281236
{
12291237
co_await launch;
12301238

1231-
auto value = co_await std::move(child.second);
1239+
auto value = co_await child.result;
12321240

1233-
if (!document.data.emplace_back(std::string { name }, std::move(value.data)))
1241+
if (!document.data.emplace_back(std::string { child.name }, std::move(value.data)))
12341242
{
12351243
std::ostringstream message;
12361244

1237-
message << "Ambiguous field error name: " << name;
1245+
message << "Ambiguous field error name: " << child.name;
12381246

1239-
document.errors.push_back({ message.str() });
1247+
auto location = (child.location ? schema_location { std::move(*child.location) }
1248+
: schema_location {});
1249+
auto path = (child.path ? error_path { std::move(*child.path) } : error_path {});
1250+
1251+
document.errors.push_back({ message.str(), std::move(location), std::move(path) });
12401252
}
12411253

12421254
if (!value.errors.empty())
@@ -1253,16 +1265,20 @@ AwaitableResolver Object::resolve(const SelectionSetParams& selectionSetParams,
12531265
std::copy(errors.begin(), errors.end(), std::back_inserter(document.errors));
12541266
}
12551267

1256-
document.data.emplace_back(std::string { name }, {});
1268+
document.data.emplace_back(std::string { child.name }, {});
12571269
}
12581270
catch (const std::exception& ex)
12591271
{
12601272
std::ostringstream message;
12611273

1262-
message << "Field error name: " << name << " unknown error: " << ex.what();
1274+
message << "Field error name: " << child.name << " unknown error: " << ex.what();
1275+
1276+
auto location = (child.location ? schema_location { std::move(*child.location) }
1277+
: schema_location {});
1278+
auto path = (child.path ? error_path { std::move(*child.path) } : error_path {});
12631279

1264-
document.errors.push_back({ message.str() });
1265-
document.data.emplace_back(std::string { name }, {});
1280+
document.errors.push_back({ message.str(), std::move(location), std::move(path) });
1281+
document.data.emplace_back(std::string { child.name }, {});
12661282
}
12671283
}
12681284

@@ -1454,8 +1470,8 @@ SubscriptionData::SubscriptionData(std::shared_ptr<OperationData> data, Subscrip
14541470
{
14551471
}
14561472

1457-
// SubscriptionDefinitionVisitor visits the AST collects the fields referenced in the subscription
1458-
// at the point where we create a subscription.
1473+
// SubscriptionDefinitionVisitor visits the AST collects the fields referenced in the
1474+
// subscription at the point where we create a subscription.
14591475
class SubscriptionDefinitionVisitor
14601476
{
14611477
public:
@@ -1680,9 +1696,9 @@ Request::Request(TypeMap operationTypes, std::shared_ptr<schema::Schema> schema)
16801696

16811697
Request::~Request()
16821698
{
1683-
// The default implementation is fine, but it can't be declared as = default because it needs to
1684-
// know how to destroy the _validation member and it can't do that with just a forward
1685-
// declaration of the class.
1699+
// The default implementation is fine, but it can't be declared as = default because it
1700+
// needs to know how to destroy the _validation member and it can't do that with just a
1701+
// forward declaration of the class.
16861702
}
16871703

16881704
std::list<schema_error> Request::validate(peg::ast& query) const
@@ -1835,8 +1851,8 @@ AwaitableSubscribe Request::subscribe(RequestSubscribeParams params)
18351851

18361852
if (itrOperation == _operations.end())
18371853
{
1838-
// There may be an empty entry in the operations map, but if it's completely missing then
1839-
// that means the schema doesn't support subscriptions at all.
1854+
// There may be an empty entry in the operations map, but if it's completely missing
1855+
// then that means the schema doesn't support subscriptions at all.
18401856
throw std::logic_error("Subscriptions not supported");
18411857
}
18421858

@@ -1897,8 +1913,8 @@ AwaitableUnsubscribe Request::unsubscribe(RequestUnsubscribeParams params)
18971913

18981914
if (itrOperation == _operations.end())
18991915
{
1900-
// There may be an empty entry in the operations map, but if it's completely missing then
1901-
// that means the schema doesn't support subscriptions at all.
1916+
// There may be an empty entry in the operations map, but if it's completely missing
1917+
// then that means the schema doesn't support subscriptions at all.
19021918
throw std::logic_error("Subscriptions not supported");
19031919
}
19041920

@@ -1948,8 +1964,8 @@ AwaitableDeliver Request::deliver(RequestDeliverParams params) const
19481964

19491965
if (itrOperation == _operations.end())
19501966
{
1951-
// There may be an empty entry in the operations map, but if it's completely missing then
1952-
// that means the schema doesn't support subscriptions at all.
1967+
// There may be an empty entry in the operations map, but if it's completely missing
1968+
// then that means the schema doesn't support subscriptions at all.
19531969
throw std::logic_error("Subscriptions not supported");
19541970
}
19551971

@@ -2211,8 +2227,8 @@ std::vector<std::shared_ptr<const SubscriptionData>> Request::collectRegistratio
22112227
const auto& subscriptionArguments = registration->arguments;
22122228
bool matchedArguments = true;
22132229

2214-
// If the field in this subscription had arguments that did not match what was
2215-
// provided in this event, don't deliver the event to this subscription
2230+
// If the field in this subscription had arguments that did not match what
2231+
// was provided in this event, don't deliver the event to this subscription
22162232
for (const auto& required : subscriptionArguments)
22172233
{
22182234
if (!(*argumentsMatch)(required))
@@ -2231,7 +2247,8 @@ std::vector<std::shared_ptr<const SubscriptionData>> Request::collectRegistratio
22312247
if (directivesMatch)
22322248
{
22332249
// If the field in this subscription had field directives that did not match
2234-
// what was provided in this event, don't deliver the event to this subscription
2250+
// what was provided in this event, don't deliver the event to this
2251+
// subscription
22352252
const auto& subscriptionFieldDirectives = registration->fieldDirectives;
22362253
bool matchedFieldDirectives = true;
22372254

0 commit comments

Comments
 (0)