// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "graphqlservice/internal/Schema.h" #include "graphqlservice/introspection/IntrospectionSchema.h" #include using namespace std::literals; namespace graphql::schema { Schema::Schema(bool noIntrospection, std::string_view description) : _noIntrospection(noIntrospection) , _description(description) { } void Schema::AddQueryType(std::shared_ptr query) { _query = query; } void Schema::AddMutationType(std::shared_ptr mutation) { _mutation = mutation; } void Schema::AddSubscriptionType(std::shared_ptr subscription) { _subscription = subscription; } void Schema::AddType(std::string_view name, std::shared_ptr type) { _typeMap[name] = _types.size(); _types.push_back({ name, type }); } bool Schema::supportsIntrospection() const noexcept { return !_noIntrospection; } const std::shared_ptr& Schema::LookupType(std::string_view name) const { auto itr = _typeMap.find(name); if (itr == _typeMap.end()) { std::ostringstream message; message << "Type not found"; if (!name.empty()) { message << " name: " << name; } throw service::schema_exception { { message.str() } }; } return _types[itr->second].second; } std::shared_ptr Schema::WrapType( introspection::TypeKind kind, std::shared_ptr ofType) { auto& wrappers = (kind == introspection::TypeKind::LIST) ? _listWrappers : _nonNullWrappers; auto& mutex = (kind == introspection::TypeKind::LIST) ? _listWrappersMutex : _nonNullWrappersMutex; std::shared_lock shared_lock { mutex }; std::unique_lock unique_lock { mutex, std::defer_lock }; auto itr = wrappers.find(ofType); if (itr == wrappers.end()) { // Trade the shared_lock for a unique_lock. shared_lock.unlock(); unique_lock.lock(); std::tie(itr, std::ignore) = wrappers.emplace(ofType, WrapperType::Make(kind, ofType)); } return itr->second; } void Schema::AddDirective(std::shared_ptr directive) { _directives.emplace_back(std::move(directive)); } std::string_view Schema::description() const noexcept { return _description; } const std::vector>>& Schema::types() const noexcept { return _types; } const std::shared_ptr& Schema::queryType() const noexcept { return _query; } const std::shared_ptr& Schema::mutationType() const noexcept { return _mutation; } const std::shared_ptr& Schema::subscriptionType() const noexcept { return _subscription; } const std::vector>& Schema::directives() const noexcept { return _directives; } BaseType::BaseType(introspection::TypeKind kind, std::string_view description) : _kind(kind) , _description(description) { } introspection::TypeKind BaseType::kind() const noexcept { return _kind; } std::string_view BaseType::name() const noexcept { return ""sv; } std::string_view BaseType::description() const noexcept { return _description; } const std::vector>& BaseType::fields() const noexcept { static const std::vector> defaultValue {}; return defaultValue; } const std::vector>& BaseType::interfaces() const noexcept { static const std::vector> defaultValue {}; return defaultValue; } const std::vector>& BaseType::possibleTypes() const noexcept { static const std::vector> defaultValue {}; return defaultValue; } const std::vector>& BaseType::enumValues() const noexcept { static const std::vector> defaultValue {}; return defaultValue; } const std::vector>& BaseType::inputFields() const noexcept { static const std::vector> defaultValue {}; return defaultValue; } const std::weak_ptr& BaseType::ofType() const noexcept { static const std::weak_ptr defaultValue; return defaultValue; } std::string_view BaseType::specifiedByURL() const noexcept { return ""sv; } struct ScalarType::init { std::string_view name; std::string_view description; std::string_view specifiedByURL; }; std::shared_ptr ScalarType::Make( std::string_view name, std::string_view description, std::string_view specifiedByURL) { return std::make_shared(init { name, description, specifiedByURL }); } ScalarType::ScalarType(init&& params) : BaseType(introspection::TypeKind::SCALAR, params.description) , _name(params.name) , _specifiedByURL(params.specifiedByURL) { } std::string_view ScalarType::name() const noexcept { return _name; } std::string_view ScalarType::specifiedByURL() const noexcept { return _specifiedByURL; } struct ObjectType::init { std::string_view name; std::string_view description; }; std::shared_ptr ObjectType::Make(std::string_view name, std::string_view description) { return std::make_shared(init { name, description }); } ObjectType::ObjectType(init&& params) : BaseType(introspection::TypeKind::OBJECT, params.description) , _name(params.name) { } void ObjectType::AddInterfaces(std::vector>&& interfaces) { _interfaces = std::move(interfaces); for (const auto& interface : _interfaces) { std::const_pointer_cast(interface)->AddPossibleType(shared_from_this()); } } void ObjectType::AddFields(std::vector>&& fields) { _fields = std::move(fields); } std::string_view ObjectType::name() const noexcept { return _name; } const std::vector>& ObjectType::fields() const noexcept { return _fields; } const std::vector>& ObjectType::interfaces() const noexcept { return _interfaces; } struct InterfaceType::init { std::string_view name; std::string_view description; }; std::shared_ptr InterfaceType::Make( std::string_view name, std::string_view description) { return std::make_shared(init { name, description }); } InterfaceType::InterfaceType(init&& params) : BaseType(introspection::TypeKind::INTERFACE, params.description) , _name(params.name) { } void InterfaceType::AddPossibleType(std::weak_ptr possibleType) { _possibleTypes.push_back(possibleType); } void InterfaceType::AddInterfaces(std::vector>&& interfaces) { _interfaces = std::move(interfaces); for (const auto& interface : _interfaces) { std::const_pointer_cast(interface)->AddPossibleType(shared_from_this()); } } void InterfaceType::AddFields(std::vector>&& fields) { _fields = std::move(fields); } std::string_view InterfaceType::name() const noexcept { return _name; } const std::vector>& InterfaceType::fields() const noexcept { return _fields; } const std::vector>& InterfaceType::possibleTypes() const noexcept { return _possibleTypes; } const std::vector>& InterfaceType::interfaces() const noexcept { return _interfaces; } struct UnionType::init { std::string_view name; std::string_view description; }; std::shared_ptr UnionType::Make(std::string_view name, std::string_view description) { return std::make_shared(init { name, description }); } UnionType::UnionType(init&& params) : BaseType(introspection::TypeKind::UNION, params.description) , _name(params.name) { } void UnionType::AddPossibleTypes(std::vector>&& possibleTypes) { _possibleTypes = std::move(possibleTypes); } std::string_view UnionType::name() const noexcept { return _name; } const std::vector>& UnionType::possibleTypes() const noexcept { return _possibleTypes; } struct EnumType::init { std::string_view name; std::string_view description; }; std::shared_ptr EnumType::Make(std::string_view name, std::string_view description) { return std::make_shared(init { name, description }); } EnumType::EnumType(init&& params) : BaseType(introspection::TypeKind::ENUM, params.description) , _name(params.name) { } void EnumType::AddEnumValues(std::vector&& enumValues) { _enumValues.resize(enumValues.size()); std::transform(enumValues.begin(), enumValues.end(), _enumValues.begin(), [](const auto& value) { return EnumValue::Make(value.value, value.description, value.deprecationReason); }); } std::string_view EnumType::name() const noexcept { return _name; } const std::vector>& EnumType::enumValues() const noexcept { return _enumValues; } struct InputObjectType::init { std::string_view name; std::string_view description; }; std::shared_ptr InputObjectType::Make( std::string_view name, std::string_view description) { return std::make_shared(init { name, description }); } InputObjectType::InputObjectType(init&& params) : BaseType(introspection::TypeKind::INPUT_OBJECT, params.description) , _name(params.name) { } void InputObjectType::AddInputValues(std::vector>&& inputValues) { _inputValues = std::move(inputValues); } std::string_view InputObjectType::name() const noexcept { return _name; } const std::vector>& InputObjectType::inputFields() const noexcept { return _inputValues; } struct WrapperType::init { introspection::TypeKind kind; std::weak_ptr ofType; }; std::shared_ptr WrapperType::Make( introspection::TypeKind kind, std::weak_ptr ofType) { return std::make_shared(init { kind, std::move(ofType) }); } WrapperType::WrapperType(init&& params) : BaseType(params.kind, std::string_view()) , _ofType(std::move(params.ofType)) { } const std::weak_ptr& WrapperType::ofType() const noexcept { return _ofType; } struct Field::init { std::string_view name; std::string_view description; std::optional deprecationReason; std::weak_ptr type; std::vector> args; }; std::shared_ptr Field::Make(std::string_view name, std::string_view description, std::optional deprecationReason, std::weak_ptr type, std::vector>&& args) { init params { name, description, deprecationReason, std::move(type), std::move(args) }; return std::make_shared(std::move(params)); } Field::Field(init&& params) : _name(params.name) , _description(params.description) , _deprecationReason(params.deprecationReason) , _type(std::move(params.type)) , _args(std::move(params.args)) { } std::string_view Field::name() const noexcept { return _name; } std::string_view Field::description() const noexcept { return _description; } const std::vector>& Field::args() const noexcept { return _args; } const std::weak_ptr& Field::type() const noexcept { return _type; } const std::optional& Field::deprecationReason() const noexcept { return _deprecationReason; } struct InputValue::init { std::string_view name; std::string_view description; std::weak_ptr type; std::string_view defaultValue; }; std::shared_ptr InputValue::Make(std::string_view name, std::string_view description, std::weak_ptr type, std::string_view defaultValue) { return std::make_shared(init { name, description, std::move(type), defaultValue }); } InputValue::InputValue(init&& params) : _name(params.name) , _description(params.description) , _type(std::move(params.type)) , _defaultValue(params.defaultValue) { } std::string_view InputValue::name() const noexcept { return _name; } std::string_view InputValue::description() const noexcept { return _description; } const std::weak_ptr& InputValue::type() const noexcept { return _type; } std::string_view InputValue::defaultValue() const noexcept { return _defaultValue; } struct EnumValue::init { std::string_view name; std::string_view description; std::optional deprecationReason; }; std::shared_ptr EnumValue::Make(std::string_view name, std::string_view description, std::optional deprecationReason) { return std::make_shared(init { name, description, deprecationReason }); } EnumValue::EnumValue(init&& params) : _name(params.name) , _description(params.description) , _deprecationReason(params.deprecationReason) { } std::string_view EnumValue::name() const noexcept { return _name; } std::string_view EnumValue::description() const noexcept { return _description; } const std::optional& EnumValue::deprecationReason() const noexcept { return _deprecationReason; } struct Directive::init { std::string_view name; std::string_view description; std::vector locations; std::vector> args; bool isRepeatable; }; std::shared_ptr Directive::Make(std::string_view name, std::string_view description, std::vector&& locations, std::vector>&& args, bool isRepeatable) { init params { name, description, std::move(locations), std::move(args), isRepeatable }; return std::make_shared(std::move(params)); } Directive::Directive(init&& params) : _name(params.name) , _description(params.description) , _locations(std::move(params.locations)) , _args(std::move(params.args)) , _isRepeatable(params.isRepeatable) { } std::string_view Directive::name() const noexcept { return _name; } std::string_view Directive::description() const noexcept { return _description; } const std::vector& Directive::locations() const noexcept { return _locations; } const std::vector>& Directive::args() const noexcept { return _args; } bool Directive::isRepeatable() const noexcept { return _isRepeatable; } } // namespace graphql::schema