@@ -410,6 +410,172 @@ class [[nodiscard("unnecessary construction")]] AwaitableScalar
410410 std::variant<T, std::future<T>, std::shared_ptr<const response::Value>> _value;
411411};
412412
413+ template <typename T>
414+ struct is_optional : std::false_type
415+ {
416+ };
417+
418+ template <typename T>
419+ struct is_optional <std::optional<T>> : std::true_type
420+ {
421+ };
422+
423+ template <typename T>
424+ struct is_vector : std::false_type
425+ {
426+ };
427+
428+ template <typename T>
429+ struct is_vector <std::vector<T>> : std::true_type
430+ {
431+ };
432+
433+ template <typename T>
434+ struct is_future : std::false_type
435+ {
436+ };
437+
438+ template <typename T>
439+ struct is_future <std::future<T>> : std::true_type
440+ {
441+ };
442+
443+ template <typename T>
444+ struct type_tag
445+ {
446+ using type = T;
447+ };
448+
449+ template <typename K, typename V>
450+ struct pair
451+ {
452+ using first_type = K;
453+ using second_type = V;
454+ };
455+
456+ template <typename Pair>
457+ struct element
458+ {
459+ static auto value (type_tag<typename Pair::first_type>) -> type_tag<typename Pair::second_type>;
460+ };
461+
462+ template <typename ... elems>
463+ struct type_map : element<elems>...
464+ {
465+ using element<elems>::value...;
466+
467+ template <typename K>
468+ using find = typename decltype (type_map::value(type_tag<K> {}))::type;
469+ };
470+
471+ template <typename U, typename T>
472+ struct GraphQLUnion : std::false_type
473+ {
474+ };
475+
476+ template <typename ... Types>
477+ struct Union
478+ {
479+ template <typename U>
480+ Union (U&& u)
481+ : value(std::forward<U>(u))
482+ {
483+ }
484+ std::variant<std::shared_ptr<Types>...> value;
485+ };
486+
487+ template <typename T>
488+ struct is_union : std::false_type
489+ {
490+ };
491+
492+ template <typename ... Types>
493+ struct is_union <Union<Types...>> : std::true_type
494+ {
495+ };
496+
497+ // helper type for the visitor #4
498+ template <class ... Ts>
499+ struct overloaded : Ts...
500+ {
501+ using Ts::operator ()...;
502+ };
503+ // explicit deduction guide (not needed as of C++20)
504+ template <class ... Ts>
505+ overloaded (Ts...) -> overloaded<Ts...>;
506+
507+ template <typename T>
508+ struct GraphQLBuilder
509+ {
510+
511+ template <typename U>
512+ static T build (U&& u)
513+ {
514+
515+ if constexpr (is_optional<T>::value)
516+ {
517+ if constexpr (is_optional<U>::value)
518+ {
519+ if (u)
520+ return GraphQLBuilder<typename T::value_type>::build (*u);
521+ return std::nullopt ;
522+ }
523+ else
524+ {
525+ return GraphQLBuilder<typename T::value_type>::build (std::forward<U>(u));
526+ }
527+ }
528+ else if constexpr (is_vector<T>::value)
529+ {
530+ T out;
531+ for (auto ui : u)
532+ {
533+ out.push_back (GraphQLBuilder<typename T::value_type>::build (ui));
534+ }
535+ return out;
536+ }
537+ else if constexpr (is_union<typename std::remove_reference_t <U>::element_type>::value)
538+ {
539+
540+ // using model_t =
541+ // typename GraphQLUnion < typename std::remove_reference_t<U>::element_type,
542+ // typename(typename T::element_type
543+ // > ::model_map)::find<typename std::remove_reference_t<V>::element_type>;
544+ // typedef std::shared_ptr<model_t> asdf_t;
545+
546+ static_assert (GraphQLUnion<typename std::remove_reference_t <U>::element_type,
547+ typename T::element_type>::value,
548+ " template<> struct GraphQLUnion<T::element_type>: std::true_type{...} not "
549+ " defined!" );
550+ if (u)
551+ return std::visit (
552+ []<typename V>(V&& arg) {
553+ using union_t = GraphQLUnion<typename std::remove_reference_t <U>::element_type, typename T::element_type>;
554+ using model_map_t = typename union_t ::model_map;
555+ using model_t = model_map_t ::template find<typename std::remove_reference_t <V>::element_type>;
556+ if constexpr (std::is_same_v<model_t , std::monostate>)
557+ {
558+ throw std::logic_error (" Unsupported variant type" );
559+ return std::shared_ptr<typename T::element_type>();
560+ }
561+ else
562+ {
563+ return GraphQLBuilder<T>::build (
564+ GraphQLBuilder<std::shared_ptr<model_t >>::build (std::move (arg)));
565+ }
566+ },
567+ std::move (u->value ));
568+ return std::shared_ptr<typename T::element_type>();
569+ }
570+ else
571+ {
572+ if (u)
573+ return std::make_shared<typename T::element_type>(std::forward<U>(u));
574+ return std::shared_ptr<typename T::element_type>();
575+ }
576+ }
577+ };
578+
413579// Field accessors may return either a result of T, an awaitable of T, or a std::future<T>, so at
414580// runtime the implementer may choose to return by value or defer/parallelize expensive operations
415581// by returning an async future or an awaitable coroutine.
@@ -418,11 +584,31 @@ class [[nodiscard("unnecessary construction")]] AwaitableObject
418584{
419585public:
420586 template <typename U>
421- AwaitableObject (U&& value)
587+ AwaitableObject (U&& value, std:: enable_if_t <std::is_assignable_v<T, U>>* = nullptr )
422588 : _value { std::forward<U>(value) }
423589 {
424590 }
425591
592+ template <typename U>
593+ AwaitableObject (
594+ U&& value, std::enable_if_t <!std::is_assignable_v<T, U> && !is_future<U>::value>* = nullptr )
595+ : _value (GraphQLBuilder<T>::build (std::forward<U>(value)))
596+ {
597+ }
598+
599+ template <typename U>
600+ AwaitableObject (
601+ U&& value, std::enable_if_t <!std::is_assignable_v<T, U> && is_future<U>::value>* = nullptr )
602+ : _value (std::async ([value = std::forward<U>(value)]() mutable {
603+ if constexpr (std::is_assignable_v<T, decltype (value.get ())>){
604+ return value.get ();
605+ }else {
606+ return GraphQLBuilder<T>::build (value.get ());
607+ }
608+ }))
609+ {
610+ }
611+
426612 struct promise_type
427613 {
428614 [[nodiscard(" unnecessary construction" )]] AwaitableObject<T> get_return_object () noexcept
0 commit comments