@@ -487,6 +487,156 @@ class [[nodiscard("unnecessary construction")]] AwaitableObject
487
487
std::variant<T, std::future<T>> _value;
488
488
};
489
489
490
+ // Type-erased visitor for resolvers.
491
+ class [[nodiscard(" unnecessary construction" )]] ResolverVisitor final
492
+ : public std::enable_shared_from_this<ResolverVisitor>
493
+ {
494
+ private:
495
+ struct Concept
496
+ {
497
+ virtual ~Concept () = default ;
498
+
499
+ virtual void add_value (std::shared_ptr<const response::Value>&& value) = 0;
500
+
501
+ virtual void reserve (std::size_t count) = 0;
502
+
503
+ virtual void start_object () = 0;
504
+ virtual void add_member (std::string&& key) = 0;
505
+ virtual void end_object () = 0;
506
+
507
+ virtual void start_array () = 0;
508
+ virtual void end_array () = 0;
509
+
510
+ virtual void add_null () = 0;
511
+ virtual void add_string (std::string&& value) = 0;
512
+ virtual void add_enum (std::string&& value) = 0;
513
+ virtual void add_id (response::IdType&& value) = 0;
514
+ virtual void add_bool (bool value) = 0;
515
+ virtual void add_int (int value) = 0;
516
+ virtual void add_float (double value) = 0;
517
+
518
+ virtual void add_error (schema_error&& error) = 0;
519
+ };
520
+
521
+ template <class T >
522
+ struct Model : Concept
523
+ {
524
+ explicit Model (std::shared_ptr<T> pimpl) noexcept
525
+ : _pimpl { std::move (pimpl) }
526
+ {
527
+ }
528
+
529
+ void add_value (std::shared_ptr<const response::Value>&& value) final
530
+ {
531
+ _pimpl->add_value (std::move (value));
532
+ }
533
+
534
+ void reserve (std::size_t count) final
535
+ {
536
+ _pimpl->reserve (count);
537
+ }
538
+
539
+ void start_object () final
540
+ {
541
+ _pimpl->start_object ();
542
+ }
543
+
544
+ void add_member (std::string&& key) final
545
+ {
546
+ _pimpl->add_member (std::move (key));
547
+ }
548
+
549
+ void end_object () final
550
+ {
551
+ _pimpl->end_object ();
552
+ }
553
+
554
+ void start_array () final
555
+ {
556
+ _pimpl->start_array ();
557
+ }
558
+
559
+ void end_array () final
560
+ {
561
+ _pimpl->end_array ();
562
+ }
563
+
564
+ void add_null () final
565
+ {
566
+ _pimpl->add_null ();
567
+ }
568
+
569
+ void add_string (std::string&& value) final
570
+ {
571
+ _pimpl->add_string (std::move (value));
572
+ }
573
+
574
+ void add_enum (std::string&& value) final
575
+ {
576
+ _pimpl->add_enum (std::move (value));
577
+ }
578
+
579
+ void add_id (response::IdType&& value) final
580
+ {
581
+ _pimpl->add_id (std::move (value));
582
+ }
583
+
584
+ void add_bool (bool value) final
585
+ {
586
+ _pimpl->add_bool (value);
587
+ }
588
+
589
+ void add_int (int value) final
590
+ {
591
+ _pimpl->add_int (value);
592
+ }
593
+
594
+ void add_float (double value) final
595
+ {
596
+ _pimpl->add_float (value);
597
+ }
598
+
599
+ void add_error (schema_error&& error) final
600
+ {
601
+ _pimpl->add_error (std::move (error));
602
+ }
603
+
604
+ private:
605
+ std::shared_ptr<T> _pimpl;
606
+ };
607
+
608
+ const std::shared_ptr<Concept> _concept;
609
+
610
+ public:
611
+ template <class T >
612
+ ResolverVisitor (std::shared_ptr<T> writer) noexcept
613
+ : _concept { std::static_pointer_cast<Concept>(
614
+ std::make_shared<Model<T>>(std::move (writer))) }
615
+ {
616
+ }
617
+
618
+ GRAPHQLSERVICE_EXPORT void add_value (std::shared_ptr<const response::Value>&& value);
619
+
620
+ GRAPHQLSERVICE_EXPORT void reserve (std::size_t count);
621
+
622
+ GRAPHQLSERVICE_EXPORT void start_object ();
623
+ GRAPHQLSERVICE_EXPORT void add_member (std::string&& key);
624
+ GRAPHQLSERVICE_EXPORT void end_object ();
625
+
626
+ GRAPHQLSERVICE_EXPORT void start_array ();
627
+ GRAPHQLSERVICE_EXPORT void end_array ();
628
+
629
+ GRAPHQLSERVICE_EXPORT void add_null ();
630
+ GRAPHQLSERVICE_EXPORT void add_string (std::string&& value);
631
+ GRAPHQLSERVICE_EXPORT void add_enum (std::string&& value);
632
+ GRAPHQLSERVICE_EXPORT void add_id (response::IdType&& value);
633
+ GRAPHQLSERVICE_EXPORT void add_bool (bool value);
634
+ GRAPHQLSERVICE_EXPORT void add_int (int value);
635
+ GRAPHQLSERVICE_EXPORT void add_float (double value);
636
+
637
+ GRAPHQLSERVICE_EXPORT void add_error (schema_error&& error);
638
+ };
639
+
490
640
// Fragments are referenced by name and have a single type condition (except for inline
491
641
// fragments, where the type condition is common but optional). They contain a set of fields
492
642
// (with optional aliases and sub-selections) and potentially references to other fragments.
@@ -535,11 +685,104 @@ struct [[nodiscard("unnecessary construction")]] ResolverParams : SelectionSetPa
535
685
const response::Value& variables;
536
686
};
537
687
688
+ // Pending token for ResolverVisitor.
689
+ struct [[nodiscard(" unnecessary construction" )]] ResultToken
690
+ {
691
+ using OpaqueValue = std::shared_ptr<const response::Value>;
692
+
693
+ struct Reserve
694
+ {
695
+ std::size_t capacity;
696
+ };
697
+
698
+ struct StartObject
699
+ {
700
+ };
701
+
702
+ struct AddMember
703
+ {
704
+ std::string key;
705
+ };
706
+
707
+ struct EndObject
708
+ {
709
+ };
710
+
711
+ struct StartArray
712
+ {
713
+ };
714
+
715
+ struct EndArray
716
+ {
717
+ };
718
+
719
+ struct NullValue
720
+ {
721
+ };
722
+
723
+ struct StringValue
724
+ {
725
+ std::string value;
726
+ };
727
+
728
+ struct EnumValue
729
+ {
730
+ std::string value;
731
+ };
732
+
733
+ struct IdValue
734
+ {
735
+ response::IdType value;
736
+ };
737
+
738
+ struct BoolValue
739
+ {
740
+ bool value;
741
+ };
742
+
743
+ struct IntValue
744
+ {
745
+ int value;
746
+ };
747
+
748
+ struct FloatValue
749
+ {
750
+ double value;
751
+ };
752
+
753
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (OpaqueValue&& value);
754
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (Reserve&& value);
755
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (StartObject&& value);
756
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (AddMember&& value);
757
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (EndObject&& value);
758
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (StartArray&& value);
759
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (EndArray&& value);
760
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (NullValue&& value);
761
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (StringValue&& value);
762
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (EnumValue&& value);
763
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (IdValue&& value);
764
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (BoolValue&& value);
765
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (IntValue&& value);
766
+ GRAPHQLSERVICE_EXPORT explicit ResultToken (FloatValue&& value);
767
+
768
+ GRAPHQLSERVICE_EXPORT void visit (const std::shared_ptr<ResolverVisitor>& visitor) &&;
769
+
770
+ private:
771
+ using variant_type =
772
+ std::variant<OpaqueValue, Reserve, StartObject, AddMember, EndObject, StartArray, EndArray,
773
+ NullValue, StringValue, EnumValue, IdValue, BoolValue, IntValue, FloatValue>;
774
+
775
+ variant_type _value;
776
+ };
777
+
538
778
// Propagate data and errors together without bundling them into a response::Value struct until
539
779
// we're ready to return from the top level Operation.
540
780
struct [[nodiscard(" unnecessary construction" )]] ResolverResult
541
781
{
542
- response::Value data;
782
+ GRAPHQLSERVICE_EXPORT response::Value toValue () &&;
783
+ GRAPHQLSERVICE_EXPORT void visit (const std::shared_ptr<ResolverVisitor>& visitor) &&;
784
+
785
+ std::list<ResultToken> data {};
543
786
std::list<schema_error> errors {};
544
787
};
545
788
@@ -1019,7 +1262,7 @@ struct ModifiedResult
1019
1262
1020
1263
if (!awaitedResult)
1021
1264
{
1022
- co_return ResolverResult {};
1265
+ co_return ResolverResult { { ResultToken { ResultToken::NullValue {} } } };
1023
1266
}
1024
1267
1025
1268
auto modifiedResult =
@@ -1046,8 +1289,8 @@ struct ModifiedResult
1046
1289
if (value)
1047
1290
{
1048
1291
ModifiedResult::validateScalar<Modifier, Other...>(*value);
1049
- co_return ResolverResult { response::Value {
1050
- std::shared_ptr { std::move (value) } } };
1292
+ co_return ResolverResult { { ResultToken {
1293
+ ResultToken::OpaqueValue { std::shared_ptr { std::move (value) } } } } };
1051
1294
}
1052
1295
}
1053
1296
@@ -1060,7 +1303,7 @@ struct ModifiedResult
1060
1303
1061
1304
if (!awaitedResult)
1062
1305
{
1063
- co_return ResolverResult {};
1306
+ co_return ResolverResult { { ResultToken { ResultToken::NullValue {} } } };
1064
1307
}
1065
1308
1066
1309
auto modifiedResult = co_await ModifiedResult::convert<Other...>(std::move (*awaitedResult),
@@ -1083,8 +1326,8 @@ struct ModifiedResult
1083
1326
if (value)
1084
1327
{
1085
1328
ModifiedResult::validateScalar<Modifier, Other...>(*value);
1086
- co_return ResolverResult { response::Value {
1087
- std::shared_ptr { std::move (value) } } };
1329
+ co_return ResolverResult { { ResultToken {
1330
+ ResultToken::OpaqueValue { std::shared_ptr { std::move (value) } } } } };
1088
1331
}
1089
1332
}
1090
1333
@@ -1128,9 +1371,10 @@ struct ModifiedResult
1128
1371
}
1129
1372
}
1130
1373
1131
- ResolverResult document { response::Value { response::Type::List } } ;
1374
+ ResolverResult document;
1132
1375
1133
- document.data .reserve (children.size ());
1376
+ document.data .push_back (ResultToken { ResultToken::StartArray {} });
1377
+ document.data .push_back (ResultToken { ResultToken::Reserve { children.size () } });
1134
1378
std::get<std::size_t >(params.errorPath ->segment ) = 0 ;
1135
1379
1136
1380
for (auto & child : children)
@@ -1141,11 +1385,11 @@ struct ModifiedResult
1141
1385
1142
1386
auto value = co_await std::move (child);
1143
1387
1144
- document.data .emplace_back ( std::move (value.data ));
1388
+ document.data .splice (document. data . end (), std::move (value.data ));
1145
1389
1146
1390
if (!value.errors .empty ())
1147
1391
{
1148
- document.errors .splice (document.errors .end (), value.errors );
1392
+ document.errors .splice (document.errors .end (), std::move ( value.errors ) );
1149
1393
}
1150
1394
}
1151
1395
catch (schema_exception& scx)
@@ -1171,6 +1415,8 @@ struct ModifiedResult
1171
1415
++std::get<std::size_t >(params.errorPath ->segment );
1172
1416
}
1173
1417
1418
+ document.data .push_back (ResultToken { ResultToken::EndArray {} });
1419
+
1174
1420
co_return document;
1175
1421
}
1176
1422
@@ -1213,7 +1459,7 @@ struct ModifiedResult
1213
1459
}
1214
1460
1215
1461
using ResolverCallback =
1216
- std::function<response::Value (typename ResultTraits<Type>::type, const ResolverParams&)>;
1462
+ std::function<ResolverResult (typename ResultTraits<Type>::type, const ResolverParams&)>;
1217
1463
1218
1464
[[nodiscard(" unnecessary call" )]] static AwaitableResolver resolve (
1219
1465
typename ResultTraits<Type>::future_type result, ResolverParams&& paramsArg,
@@ -1226,7 +1472,8 @@ struct ModifiedResult
1226
1472
if (value)
1227
1473
{
1228
1474
Result<Type>::validateScalar (*value);
1229
- co_return ResolverResult { response::Value { std::shared_ptr { std::move (value) } } };
1475
+ co_return ResolverResult { { ResultToken {
1476
+ ResultToken::OpaqueValue { std::shared_ptr { std::move (value) } } } } };
1230
1477
}
1231
1478
1232
1479
auto pendingResolver = std::move (resolver);
@@ -1238,7 +1485,14 @@ struct ModifiedResult
1238
1485
try
1239
1486
{
1240
1487
co_await params.launch ;
1241
- document.data = pendingResolver (co_await result, params);
1488
+ auto value = pendingResolver (co_await result, params);
1489
+
1490
+ document.data .splice (document.data .end (), std::move (value.data ));
1491
+
1492
+ if (!value.errors .empty ())
1493
+ {
1494
+ document.errors .splice (document.errors .end (), std::move (value.errors ));
1495
+ }
1242
1496
}
1243
1497
catch (schema_exception& scx)
1244
1498
{
0 commit comments