Class: GraphQL::Stitching::Composer
- Inherits:
-
Object
- Object
- GraphQL::Stitching::Composer
- Defined in:
- lib/graphql/stitching/composer.rb
Defined Under Namespace
Classes: BaseValidator, ComposerError, ValidateBoundaries, ValidateInterfaces, ValidationError
Constant Summary collapse
- NO_DEFAULT_VALUE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
begin class T < GraphQL::Schema::Object field(:f, String) do argument(:a, String) end end T.get_field("f").get_argument("a").default_value end
- BASIC_VALUE_MERGER =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
->(values_by_location, _info) { values_by_location.values.find { !_1.nil? } }
- BASIC_ROOT_FIELD_LOCATION_SELECTOR =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
->(locations, _info) { locations.last }
- VALIDATORS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
[ "ValidateInterfaces", "ValidateBoundaries", ].freeze
Instance Attribute Summary collapse
- #candidate_types_by_name_and_location ⇒ Object readonly private
-
#mutation_name ⇒ String
readonly
Name of the Mutation type in the composed schema.
-
#query_name ⇒ String
readonly
Name of the Query type in the composed schema.
- #schema_directives ⇒ Object readonly private
Instance Method Summary collapse
-
#initialize(query_name: "Query", mutation_name: "Mutation", description_merger: nil, deprecation_merger: nil, default_value_merger: nil, directive_kwarg_merger: nil, root_field_location_selector: nil) ⇒ Composer
constructor
A new instance of Composer.
- #perform(locations_input) ⇒ Object
Constructor Details
#initialize(query_name: "Query", mutation_name: "Mutation", description_merger: nil, deprecation_merger: nil, default_value_merger: nil, directive_kwarg_merger: nil, root_field_location_selector: nil) ⇒ Composer
Returns a new instance of Composer.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/graphql/stitching/composer.rb', line 44 def initialize( query_name: "Query", mutation_name: "Mutation", description_merger: nil, deprecation_merger: nil, default_value_merger: nil, directive_kwarg_merger: nil, root_field_location_selector: nil ) @query_name = query_name @mutation_name = mutation_name @description_merger = description_merger || BASIC_VALUE_MERGER @deprecation_merger = deprecation_merger || BASIC_VALUE_MERGER @default_value_merger = default_value_merger || BASIC_VALUE_MERGER @directive_kwarg_merger = directive_kwarg_merger || BASIC_VALUE_MERGER @root_field_location_selector = root_field_location_selector || BASIC_ROOT_FIELD_LOCATION_SELECTOR @stitch_directives = {} @field_map = nil @boundary_map = nil @mapped_type_names = nil @candidate_directives_by_name_and_location = nil @schema_directives = nil end |
Instance Attribute Details
#candidate_types_by_name_and_location ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
39 40 41 |
# File 'lib/graphql/stitching/composer.rb', line 39 def candidate_types_by_name_and_location @candidate_types_by_name_and_location end |
#mutation_name ⇒ String (readonly)
Returns name of the Mutation type in the composed schema.
36 37 38 |
# File 'lib/graphql/stitching/composer.rb', line 36 def mutation_name @mutation_name end |
#query_name ⇒ String (readonly)
Returns name of the Query type in the composed schema.
33 34 35 |
# File 'lib/graphql/stitching/composer.rb', line 33 def query_name @query_name end |
#schema_directives ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
42 43 44 |
# File 'lib/graphql/stitching/composer.rb', line 42 def schema_directives @schema_directives end |
Instance Method Details
#perform(locations_input) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/graphql/stitching/composer.rb', line 69 def perform(locations_input) reset! schemas, executables = prepare_locations_input(locations_input) # "directive_name" => "location" => candidate_directive @candidate_directives_by_name_and_location = schemas.each_with_object({}) do |(location, schema), memo| (schema.directives.keys - schema.default_directives.keys - GraphQL::Stitching.stitching_directive_names).each do |directive_name| memo[directive_name] ||= {} memo[directive_name][location] = schema.directives[directive_name] end end # "directive_name" => merged_directive @schema_directives = @candidate_directives_by_name_and_location.each_with_object({}) do |(directive_name, directives_by_location), memo| memo[directive_name] = build_directive(directive_name, directives_by_location) end @schema_directives.merge!(GraphQL::Schema.default_directives) # "Typename" => "location" => candidate_type @candidate_types_by_name_and_location = schemas.each_with_object({}) do |(location, schema), memo| raise ComposerError, "Location keys must be strings" unless location.is_a?(String) raise ComposerError, "The subscription operation is not supported." if schema.subscription introspection_types = schema.introspection_system.types.keys schema.types.each do |type_name, type_candidate| next if introspection_types.include?(type_name) if type_name == @query_name && type_candidate != schema.query raise ComposerError, "Query name \"#{@query_name}\" is used by non-query type in #{location} schema." elsif type_name == @mutation_name && type_candidate != schema.mutation raise ComposerError, "Mutation name \"#{@mutation_name}\" is used by non-mutation type in #{location} schema." end type_name = @query_name if type_candidate == schema.query type_name = @mutation_name if type_candidate == schema.mutation @mapped_type_names[type_candidate.graphql_name] = type_name if type_candidate.graphql_name != type_name memo[type_name] ||= {} memo[type_name][location] = type_candidate end end enum_usage = build_enum_usage_map(schemas.values) # "Typename" => merged_type schema_types = @candidate_types_by_name_and_location.each_with_object({}) do |(type_name, types_by_location), memo| kinds = types_by_location.values.map { _1.kind.name }.tap(&:uniq!) if kinds.length > 1 raise ComposerError, "Cannot merge different kinds for `#{type_name}`. Found: #{kinds.join(", ")}." end extract_boundaries(type_name, types_by_location) if type_name == @query_name memo[type_name] = case kinds.first when "SCALAR" build_scalar_type(type_name, types_by_location) when "ENUM" build_enum_type(type_name, types_by_location, enum_usage) when "OBJECT" build_object_type(type_name, types_by_location) when "INTERFACE" build_interface_type(type_name, types_by_location) when "UNION" build_union_type(type_name, types_by_location) when "INPUT_OBJECT" build_input_object_type(type_name, types_by_location) else raise ComposerError, "Unexpected kind encountered for `#{type_name}`. Found: #{kinds.first}." end end builder = self schema = Class.new(GraphQL::Schema) do orphan_types schema_types.values query schema_types[builder.query_name] mutation schema_types[builder.mutation_name] directives builder.schema_directives.values own_orphan_types.clear end select_root_field_locations(schema) (schema) supergraph = Supergraph.new( schema: schema, fields: @field_map, boundaries: @boundary_map, executables: executables, ) VALIDATORS.each do |validator| klass = Object.const_get("GraphQL::Stitching::Composer::#{validator}") klass.new.perform(supergraph, self) end supergraph end |