Class: ElasticGraph::SchemaDefinition::SchemaElements::TypeReference
- Inherits:
-
Object
- Object
- ElasticGraph::SchemaDefinition::SchemaElements::TypeReference
- Extended by:
- Forwardable
- Defined in:
- lib/elastic_graph/schema_definition/schema_elements/type_reference.rb
Overview
Represents a reference to a type. This is basically just a name of a type, with the ability to resolve it to an actual type object on demand. In addition, we provide some useful logic that is based entirely on the type name.
This is necessary because GraphQL does not require that types are defined before they are referenced. (And also you can have circular type dependencies). Therefore, we need to use a reference to a type initially, and can later resolve it to a concrete type object as needed.
Constant Summary collapse
- STATIC_FORMAT_NAME_BY_CATEGORY =
Most of ElasticGraph’s derived GraphQL types have a static suffix (e.g. the full type name is source_type + suffix). This is a map of all of these.
TypeNamer::REQUIRED_PLACEHOLDERS.filter_map do |format_name, placeholders| if placeholders == [:base] as_snake_case = SchemaArtifacts::RuntimeMetadata::SchemaElementNamesDefinition::SnakeCaseConverter .normalize_case(format_name.to_s) .delete_prefix("_") [as_snake_case.to_sym, format_name] end end.to_h
Instance Method Summary collapse
-
#as_aggregation_sub_aggregations(parent_doc_types: [fully_unwrapped.name], field_path: []) ⇒ Object
Generates the type name used for a ‘sub_aggregations` field.
-
#as_object_type ⇒ Object
Returns the ‘ObjectType`, `UnionType` or `InterfaceType` object to which this type name refers, if it is the name of one of those kinds of types.
- #as_parent_aggregation(parent_doc_types:) ⇒ Object
-
#as_static_derived_type(category) ⇒ Object
Builds a ‘TypeReference` for a statically named derived type for the given `category.
-
#as_sub_aggregation(parent_doc_types:) ⇒ Object
Generates the type name used for a sub-aggregation.
- #boolean? ⇒ Boolean
- #enum? ⇒ Boolean
-
#fully_unwrapped ⇒ Object
Extracts the type without any non-null or list wrappings it has.
-
#json_schema_layers ⇒ Object
Returns all the JSON schema array/nullable layers of a type, from outermost to innermost.
-
#leaf? ⇒ Boolean
Returns ‘true` if this is known to be a scalar type or enum type.
-
#list? ⇒ Boolean
Returns ‘true` if this is a list type.
- #list_element_filter_input? ⇒ Boolean
- #list_filter_input? ⇒ Boolean
-
#non_null? ⇒ Boolean
Returns ‘true` if this is a non-null type.
-
#object? ⇒ Boolean
Returns ‘true` if this is known to be an object type of some sort (including interface types, union types, and proper object types).
- #resolved ⇒ Object
-
#scalar_type_needing_grouped_by_object? ⇒ Boolean
Generally speaking, scalar types have ‘grouped_by` fields which are scalars of the same types, and object types have `grouped_by` fields which are special `[object_type]GroupedBy` types.
-
#to_final_form(as_input: false) ⇒ Object
Converts the TypeReference to its final form (i.e. the from that will be used in rendered schema artifacts).
- #to_s ⇒ Object
-
#unwrap_list ⇒ Object
Removes the list wrapping if this is a list.
-
#unwrap_non_null ⇒ Object
Removes any non-null wrappings the type has.
- #unwrapped_name ⇒ Object
-
#with_reverted_override ⇒ Object
Returns a new ‘TypeReference` with any type name overrides reverted (to provide the “original” type name).
- #wrap_non_null ⇒ Object
Instance Method Details
#as_aggregation_sub_aggregations(parent_doc_types: [fully_unwrapped.name], field_path: []) ⇒ Object
Generates the type name used for a ‘sub_aggregations` field. A `sub_aggregations` field is available alongside `grouped_by`, `count`, and `aggregated_values` on an aggregation or sub-aggregation node. This type is used in two situations:
-
It is used directly under ‘nodes`/`edges { node }` on an Aggregation or SubAggregation. It provides access to each of the sub-aggregations that are available in that context.
-
It is used underneath that ‘SubAggregations` object for single object fields which have fields under them that are sub-aggregatable.
The fields (and types of those fields) used for one of these types is contextual based on what the parent doc types are (so that we can offer sub-aggregations of the parent doc types!) and the field path (for the 2nd case).
257 258 259 260 261 262 263 264 265 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 257 def as_aggregation_sub_aggregations(parent_doc_types: [fully_unwrapped.name], field_path: []) field_part = field_path.map { |f| to_title_case(f.name) }.join renamed_with_same_wrappings(type_namer.generate_name_for( :SubAggregations, parent_agg_type: parent_aggregation_type(parent_doc_types), field_path: field_part )) end |
#as_object_type ⇒ Object
Returns the ‘ObjectType`, `UnionType` or `InterfaceType` object to which this type name refers, if it is the name of one of those kinds of types.
Ignores any non-null wrapping on the type, if there is one.
61 62 63 64 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 61 def as_object_type type = _ = unwrap_non_null.resolved type if type.respond_to?(:graphql_fields_by_name) end |
#as_parent_aggregation(parent_doc_types:) ⇒ Object
267 268 269 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 267 def as_parent_aggregation(parent_doc_types:) schema_def_state.type_ref(parent_aggregation_type(parent_doc_types)) end |
#as_static_derived_type(category) ⇒ Object
Builds a ‘TypeReference` for a statically named derived type for the given `category.
In addition, a dynamic method ‘as_` is also provided (defined further below).
222 223 224 225 226 227 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 222 def as_static_derived_type(category) renamed_with_same_wrappings(type_namer.generate_name_for( STATIC_FORMAT_NAME_BY_CATEGORY.fetch(category), base: fully_unwrapped.name )) end |
#as_sub_aggregation(parent_doc_types:) ⇒ Object
Generates the type name used for a sub-aggregation. This type has ‘grouped_by`, `aggregated_values`, `count` and `sub_aggregations` sub-fields to expose the different bits of aggregation functionality.
The type name is based both on the type reference name and on the set of ‘parent_doc_types` that exist above it. The `parent_doc_types` are used in the name because we plan to offer different sub-aggregations under it based on where it is in the document structure. A type which is `nested` at multiple levels in different document contexts needs separate types generated for each case so that we can offer the correct contextual sub-aggregations that can be offered for each case.
237 238 239 240 241 242 243 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 237 def as_sub_aggregation(parent_doc_types:) renamed_with_same_wrappings(type_namer.generate_name_for( :SubAggregation, base: fully_unwrapped.name, parent_types: parent_doc_types.join )) end |
#boolean? ⇒ Boolean
143 144 145 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 143 def boolean? name == "Boolean" end |
#enum? ⇒ Boolean
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 96 def enum? return unwrap_non_null.enum? if non_null? if (resolved_type = resolved) return resolved_type.is_a?(EnumType) end # For derived GraphQL types, the name usually implies what kind of type it is. # The derived types get generated last, so this prediate may be called before the # type has been defined. case schema_kind_implied_by_name when :object false when :enum true else if block_given? yield else # If we can't determine the type from the name, just raise an error. raise Errors::SchemaError, "Type `#{name}` cannot be resolved. Is it misspelled?" end end end |
#fully_unwrapped ⇒ Object
Extracts the type without any non-null or list wrappings it has.
36 37 38 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 36 def fully_unwrapped schema_def_state.type_ref(unwrapped_name) end |
#json_schema_layers ⇒ Object
Returns all the JSON schema array/nullable layers of a type, from outermost to innermost. For example, [[Int]] will return [:nullable, :array, :nullable, :array, :nullable]
176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 176 def json_schema_layers @json_schema_layers ||= begin layers, inner_type = peel_json_schema_layers_once if layers.empty? || inner_type == self layers else layers + inner_type.json_schema_layers end end end |
#leaf? ⇒ Boolean
Returns ‘true` if this is known to be a scalar type or enum type. Returns `false` if this is known to be an object type or list type of any sort.
Raises an error if it cannot be determined either from the name or by resolving the type.
Ignores any non-null wrapping on the type, if there is one.
127 128 129 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 127 def leaf? !list? && !object? end |
#list? ⇒ Boolean
Returns ‘true` if this is a list type.
Ignores any non-null wrapping on the type, if there is one.
134 135 136 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 134 def list? name.start_with?("[") end |
#list_element_filter_input? ⇒ Boolean
283 284 285 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 283 def list_element_filter_input? matches_format_of?(:list_element_filter_input) end |
#list_filter_input? ⇒ Boolean
279 280 281 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 279 def list_filter_input? matches_format_of?(:list_filter_input) end |
#non_null? ⇒ Boolean
Returns ‘true` if this is a non-null type.
139 140 141 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 139 def non_null? name.end_with?("!") end |
#object? ⇒ Boolean
Returns ‘true` if this is known to be an object type of some sort (including interface types, union types, and proper object types).
Returns ‘false` if this is known to be a leaf type of some sort (either a scalar or enum). Returns `false` if this is a list type (either a list of objects or leafs).
Raises an error if it cannot be determined either from the name or by resolving the type.
Ignores any non-null wrapping on the type, if there is one.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 75 def object? return unwrap_non_null.object? if non_null? if (resolved_type = resolved) return resolved_type.respond_to?(:graphql_fields_by_name) end # For derived GraphQL types, the name usually implies what kind of type it is. # The derived types get generated last, so this prediate may be called before the # type has been defined. case schema_kind_implied_by_name when :object true when :enum false else # If we can't determine the type from the name, just raise an error. raise Errors::SchemaError, "Type `#{name}` cannot be resolved. Is it misspelled?" end end |
#resolved ⇒ Object
151 152 153 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 151 def resolved schema_def_state.types_by_name[name] end |
#scalar_type_needing_grouped_by_object? ⇒ Boolean
Generally speaking, scalar types have ‘grouped_by` fields which are scalars of the same types, and object types have `grouped_by` fields which are special `[object_type]GroupedBy` types.
…except for some special cases (Date and DateTime), which this predicate detects.
165 166 167 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 165 def scalar_type_needing_grouped_by_object? %w[Date DateTime].include?(type_namer.revert_override_for(name)) end |
#to_final_form(as_input: false) ⇒ Object
Converts the TypeReference to its final form (i.e. the from that will be used in rendered schema artifacts). This handles multiple bits of type name customization based on the configured ‘type_name_overrides` and `derived_type_name_formats` settings (via the `TypeNamer`):
-
If the ‘as_input` is `true` and this is a reference to an enum type, converts to the `InputEnum` format.
-
If there is a configured name override that applies to this type, uses it.
206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 206 def to_final_form(as_input: false) unwrapped = fully_unwrapped inner_name = type_namer.name_for(unwrapped.name) if as_input && schema_def_state.type_ref(inner_name).enum? inner_name = type_namer.name_for( type_namer.generate_name_for(:InputEnum, base: inner_name) ) end renamed_with_same_wrappings(inner_name) end |
#to_s ⇒ Object
147 148 149 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 147 def to_s name end |
#unwrap_list ⇒ Object
Removes the list wrapping if this is a list.
If the outer wrapping is non-null, unwraps that as well.
53 54 55 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 53 def unwrap_list schema_def_state.type_ref(unwrap_non_null.name.delete_prefix("[").delete_suffix("]")) end |
#unwrap_non_null ⇒ Object
Removes any non-null wrappings the type has.
41 42 43 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 41 def unwrap_non_null schema_def_state.type_ref(name.delete_suffix("!")) end |
#unwrapped_name ⇒ Object
155 156 157 158 159 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 155 def unwrapped_name name .sub(/\A\[+/, "") # strip `[` characters from the start: https://rubular.com/r/tHVBBQkQUMMVVz .sub(/[\]!]+\z/, "") # strip `]` and `!` characters from the end: https://rubular.com/r/pC8C0i7EpvHDbf end |
#with_reverted_override ⇒ Object
Returns a new ‘TypeReference` with any type name overrides reverted (to provide the “original” type name).
170 171 172 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 170 def with_reverted_override schema_def_state.type_ref(type_namer.revert_override_for(name)) end |
#wrap_non_null ⇒ Object
45 46 47 48 |
# File 'lib/elastic_graph/schema_definition/schema_elements/type_reference.rb', line 45 def wrap_non_null return self if non_null? schema_def_state.type_ref("#{name}!") end |