Class: ElasticGraph::GraphQL::Schema::Type
- Inherits:
-
Object
- Object
- ElasticGraph::GraphQL::Schema::Type
- Extended by:
- Forwardable
- Defined in:
- lib/elastic_graph/graphql/schema/type.rb
Overview
Represents a GraphQL type.
Instance Attribute Summary collapse
-
#elasticgraph_category ⇒ Object
readonly
Returns the value of attribute elasticgraph_category.
-
#fields_by_name ⇒ Object
readonly
Returns the value of attribute fields_by_name.
-
#graphql_only_return_type ⇒ Object
readonly
Returns the value of attribute graphql_only_return_type.
-
#graphql_type ⇒ Object
readonly
Returns the value of attribute graphql_type.
-
#grouping_missing_value_placeholder ⇒ String, ...
readonly
Returns the grouping missing value placeholder for this type, if one is defined.
-
#index_definitions ⇒ Object
readonly
Returns the value of attribute index_definitions.
Instance Method Summary collapse
- #abstract? ⇒ Boolean
- #coerce_result(result) ⇒ Object
- #collection? ⇒ Boolean
-
#embedded_object? ⇒ Boolean
Indicates if this type is an object type that is embedded in another indexed type in the index mapping.
- #enum? ⇒ Boolean
- #enum_value_named(enum_value_name) ⇒ Object
- #field_named(field_name) ⇒ Object
- #fields_by_name_in_index ⇒ Object
-
#hidden_from_queries? ⇒ Boolean
Indicates this type should be hidden in the GraphQL schema so as to not be queryable.
- #indexed_aggregation? ⇒ Boolean
-
#indexed_document? ⇒ Boolean
Is the type a user-defined document type directly indexed in the index?.
-
#initialize(schema, graphql_type, index_definitions, object_runtime_metadata, enum_runtime_metadata, scalar_runtime_metadata, resolvers_needing_lookahead) ⇒ Type
constructor
A new instance of Type.
- #name ⇒ Object
- #nullable? ⇒ Boolean
-
#object? ⇒ Boolean
Returns ‘true` if this type serializes as a JSON object, with sub-fields.
- #relay_connection? ⇒ Boolean
- #relay_edge? ⇒ Boolean
-
#search_index_definitions ⇒ Object
(also: #indexing_index_definitions)
List of index definitions that should be searched for this type.
-
#shares_index_with_non_subtypes? ⇒ Boolean
Returns true if any of this type’s search indexes contain any concrete document types that are not subtypes of this type.
-
#source_type ⇒ Object
For derived types (e.g. indexed aggregations), returns the underlying source document type.
-
#subtypes ⇒ Object
Returns all concrete subtypes, at any depth.
- #to_s ⇒ Object (also: #inspect)
-
#unwrap_fully ⇒ Object
Fully unwraps this type, in order to extracts the underlying type (an object or scalar) from its wrappings.
-
#unwrap_non_null ⇒ Object
Unwraps the non-null type wrapping, if this type is non-null.
Constructor Details
#initialize(schema, graphql_type, index_definitions, object_runtime_metadata, enum_runtime_metadata, scalar_runtime_metadata, resolvers_needing_lookahead) ⇒ Type
Returns a new instance of Type.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 28 def initialize( schema, graphql_type, index_definitions, , , , resolvers_needing_lookahead ) @schema = schema @graphql_type = graphql_type @enum_values_by_name = Hash.new do |hash, key| hash[key] = lookup_enum_value_by_name(key) end @index_definitions = index_definitions @object_runtime_metadata = @elasticgraph_category = &.elasticgraph_category @graphql_only_return_type = &.graphql_only_return_type @enum_runtime_metadata = @resolvers_needing_lookahead = resolvers_needing_lookahead @enum_value_names_by_original_name = (&.values_by_name || {}).to_h do |name, value| [value.alternate_original_name || name, name] end @fields_by_name = build_fields_by_name_hash(schema, graphql_type).freeze @grouping_missing_value_placeholder = determine_grouping_missing_value_placeholder(&.grouping_missing_value_placeholder) end |
Instance Attribute Details
#elasticgraph_category ⇒ Object (readonly)
Returns the value of attribute elasticgraph_category.
20 21 22 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20 def elasticgraph_category @elasticgraph_category end |
#fields_by_name ⇒ Object (readonly)
Returns the value of attribute fields_by_name.
20 21 22 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20 def fields_by_name @fields_by_name end |
#graphql_only_return_type ⇒ Object (readonly)
Returns the value of attribute graphql_only_return_type.
20 21 22 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20 def graphql_only_return_type @graphql_only_return_type end |
#graphql_type ⇒ Object (readonly)
Returns the value of attribute graphql_type.
20 21 22 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20 def graphql_type @graphql_type end |
#grouping_missing_value_placeholder ⇒ String, ... (readonly)
Returns the grouping missing value placeholder for this type, if one is defined. This is used to handle missing values in aggregations without creating separate missing subaggregations, reducing the exponential explosion of subaggregations.
26 27 28 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 26 def grouping_missing_value_placeholder @grouping_missing_value_placeholder end |
#index_definitions ⇒ Object (readonly)
Returns the value of attribute index_definitions.
20 21 22 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 20 def index_definitions @index_definitions end |
Instance Method Details
#abstract? ⇒ Boolean
205 206 207 208 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 205 def abstract? return unwrap_non_null.abstract? if non_null? @graphql_type.kind.abstract? end |
#coerce_result(result) ⇒ Object
173 174 175 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 173 def coerce_result(result) @enum_value_names_by_original_name.fetch(result, result) end |
#collection? ⇒ Boolean
247 248 249 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 247 def collection? list? || relay_connection? end |
#embedded_object? ⇒ Boolean
Indicates if this type is an object type that is embedded in another indexed type in the index mapping. Note: we have avoided the term ‘nested` here because it is a specific Elasticsearch/OpenSearch mapping type that we will not necessarily be using: www.elastic.co/guide/en/elasticsearch/reference/current/nested.html
241 242 243 244 245 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 241 def return unwrap_non_null. if non_null? return false if relay_edge? || relay_connection? || @graphql_type.kind.input_object? object? && !indexed_document? && !indexed_aggregation? end |
#enum? ⇒ Boolean
210 211 212 213 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 210 def enum? return unwrap_non_null.enum? if non_null? @graphql_type.kind.enum? end |
#enum_value_named(enum_value_name) ⇒ Object
169 170 171 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 169 def enum_value_named(enum_value_name) @enum_values_by_name[enum_value_name] end |
#field_named(field_name) ⇒ Object
157 158 159 160 161 162 163 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 157 def field_named(field_name) @fields_by_name.fetch(field_name) rescue KeyError => e msg = "No field named #{field_name} (on type #{name}) could be found" msg += "; Possible alternatives: [#{e.corrections.join(", ").delete('"')}]." if e.corrections.any? raise Errors::NotFoundError, msg end |
#fields_by_name_in_index ⇒ Object
165 166 167 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 165 def fields_by_name_in_index @fields_by_name_in_index ||= @fields_by_name.values.group_by(&:name_in_index) end |
#hidden_from_queries? ⇒ Boolean
Indicates this type should be hidden in the GraphQL schema so as to not be queryable. We only hide a type if both of the following are true:
-
It’s backed by one or more search index definitions
-
None of the search index definitions are accessible from queries
264 265 266 267 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 264 def hidden_from_queries? return false if search_index_definitions.empty? search_index_definitions.none?(&:accessible_from_queries?) end |
#indexed_aggregation? ⇒ Boolean
233 234 235 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 233 def indexed_aggregation? unwrapped_has_category?(:indexed_aggregation) end |
#indexed_document? ⇒ Boolean
Is the type a user-defined document type directly indexed in the index?
226 227 228 229 230 231 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 226 def indexed_document? return unwrap_non_null.indexed_document? if non_null? return false if indexed_aggregation? return true if subtypes.any? && subtypes.all?(&:indexed_document?) @index_definitions.any? end |
#name ⇒ Object
57 58 59 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 57 def name @name ||= @graphql_type.to_type_signature end |
#nullable? ⇒ Boolean
201 202 203 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 201 def nullable? !non_null? end |
#object? ⇒ Boolean
Returns ‘true` if this type serializes as a JSON object, with sub-fields. Note this is slightly different from the GraphQL gem and GraphQL spec: it considers inputs to be distinct from objects, but for our purposes we consider inputs to be objects since they have sub-fields and serialize as JSON objects.
219 220 221 222 223 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 219 def object? return unwrap_non_null.object? if non_null? kind = @graphql_type.kind kind.abstract? || kind.object? || kind.input_object? end |
#relay_connection? ⇒ Boolean
251 252 253 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 251 def relay_connection? unwrapped_has_category?(:relay_connection) end |
#relay_edge? ⇒ Boolean
255 256 257 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 255 def relay_edge? unwrapped_has_category?(:relay_edge) end |
#search_index_definitions ⇒ Object Also known as: indexing_index_definitions
List of index definitions that should be searched for this type.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 62 def search_index_definitions @search_index_definitions ||= if (st = source_type) # When a type has a source type (a prime example being indexed aggregations), we delegate # to the source type. This works better than dumping index definitions in the runtime metadata # of the derived type itself because of abstract (interface/union) types. The source document # type handles that (since there is a supertype/subtype relationship on the document types) # but that relationship does not exist on derived types. # # For example, assume we have these indexed document types: # - type Person {} # - type Company {} # - union Inventor = Person | Company # # We can go from `Inventor` to its subtypes to find the search indexes. However, `InventorAggregation` # is NOT a union of `PersonAggregation` and `CompanyAggregation`, so we can't do the same thing on the # indexed aggregation types. Delegating to the source type solves this case. st.search_index_definitions elsif abstract? # For abstract types, derive search indexes purely from concrete subtypes. This correctly # handles cases where subtypes override the abstract type's declared index with a dedicated # one — only indexes that actually contain documents for this type are searched. # Note: subtypes returns all concrete subtypes at any depth, so no explicit recursion is needed. subtypes.flat_map(&:search_index_definitions).to_set else @index_definitions end end |
#shares_index_with_non_subtypes? ⇒ Boolean
Returns true if any of this type’s search indexes contain any concrete document types that are not subtypes of this type. Used to determine whether a ‘__typename` filter is needed when querying an abstract type.
147 148 149 150 151 152 153 154 155 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 147 def shares_index_with_non_subtypes? return @shares_index_with_non_subtypes if defined?(@shares_index_with_non_subtypes) @shares_index_with_non_subtypes = search_index_definitions.any? do |index_def| @schema.document_types_stored_in(index_def.name).any? do |t| t != self && !subtypes.include?(t) && !t.abstract? end end end |
#source_type ⇒ Object
For derived types (e.g. indexed aggregations), returns the underlying source document type. Returns ‘nil` for non-derived types.
139 140 141 142 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 139 def source_type return @source_type if defined?(@source_type) @source_type = @object_runtime_metadata&.source_type&.then { |st| @schema.type_named(st) } end |
#subtypes ⇒ Object
Returns all concrete subtypes, at any depth. This is like ‘#possible_types` provided by the GraphQL gem, but that includes a type itself when you ask for the possible types of a non-abstract type.
128 129 130 131 132 133 134 135 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 128 def subtypes @subtypes ||= @schema .graphql_schema .possible_types(graphql_type, visibility_profile: :boot) .map { |t| @schema.type_from(t) } .reject { |t| t == self } .to_set end |
#to_s ⇒ Object Also known as: inspect
177 178 179 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 177 def to_s "#<#{self.class.name} #{name}>" end |
#unwrap_fully ⇒ Object
Fully unwraps this type, in order to extracts the underlying type (an object or scalar) from its wrappings. As needed, this will unwrap any of these wrappings:
- non-null
- list
- relay connection
112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 112 def unwrap_fully @unwrap_fully ||= begin unwrapped = @schema.type_from(@graphql_type.unwrap) if unwrapped.relay_connection? unwrapped .field_named(@schema.element_names.edges).type.unwrap_fully .field_named(@schema.element_names.node).type.unwrap_fully else unwrapped end end end |
#unwrap_non_null ⇒ Object
Unwraps the non-null type wrapping, if this type is non-null. If this type is nullable, returns it as-is.
101 102 103 104 |
# File 'lib/elastic_graph/graphql/schema/type.rb', line 101 def unwrap_non_null return self if nullable? @schema.type_from(@graphql_type.of_type) end |