Module: ElasticGraph::SchemaDefinition::Mixins::ImplementsInterfaces
- Included in:
- SchemaElements::InterfaceType, SchemaElements::ObjectType
- Defined in:
- lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb
Overview
Mixin for types that can implement interfaces (SchemaElements::ObjectType and SchemaElements::InterfaceType).
Instance Method Summary collapse
-
#implemented_interfaces ⇒ Array<SchemaElements::TypeReference>
List of type references for the interface types implemented by this type.
-
#implements(*interface_names) ⇒ void
Declares that the current type implements the specified interface, making the current type a subtype of the interface.
-
#recursively_resolve_supertypes ⇒ Set<UnionType, InterfaceType>
Returns all supertypes of this type, including union memberships and interface ancestors.
-
#to_sdl {|SchemaElements::Argument| ... } ⇒ String
SDL string of the type.
-
#verify_graphql_correctness! ⇒ void
Called after the schema definition is complete, before dumping artifacts.
Instance Method Details
#implemented_interfaces ⇒ Array<SchemaElements::TypeReference>
Returns list of type references for the interface types implemented by this type.
59 60 61 |
# File 'lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb', line 59 def implemented_interfaces @implemented_interfaces ||= [] end |
#implements(*interface_names) ⇒ void
If the named interface has declared an index (via HasIndices#index), calling ‘implements` causes this type to automatically inherit that index — it will be stored in the same datastore index as all other implementations of the named interface. To use a dedicated index instead, call HasIndices#index on this type.
This method returns an undefined value.
Declares that the current type implements the specified interface, making the current type a subtype of the interface. The current type must define all of the fields of the named interface, with the exact same field types.
47 48 49 50 51 52 53 54 55 56 |
# File 'lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb', line 47 def implements(*interface_names) interface_refs = interface_names.map do |interface_name| schema_def_state.type_ref(interface_name).to_final_form.tap do |interface_ref| implementations = schema_def_state.implementations_by_interface_ref[interface_ref] # : ::Set[SchemaElements::TypeWithSubfields] implementations << self end end implemented_interfaces.concat(interface_refs) end |
#recursively_resolve_supertypes ⇒ Set<UnionType, InterfaceType>
Returns all supertypes of this type, including union memberships and interface ancestors.
131 132 133 134 |
# File 'lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb', line 131 def recursively_resolve_supertypes union_memberships = schema_def_state.union_types_by_member_ref[type_ref] # : ::Set[abstractType] union_memberships | recursively_resolve_interface_supertypes end |
#to_sdl {|SchemaElements::Argument| ... } ⇒ String
Returns SDL string of the type.
114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb', line 114 def to_sdl(&field_arg_selector) name_section = if implemented_interfaces.empty? name else # Include all ancestor interfaces in SDL all_interfaces = recursively_resolve_supertypes.grep(SchemaElements::InterfaceType) "#{name} implements #{all_interfaces.map(&:name).sort.join(" & ")}" end generate_sdl(name_section: name_section, &field_arg_selector) end |
#verify_graphql_correctness! ⇒ void
This method returns an undefined value.
Called after the schema definition is complete, before dumping artifacts. Here we validate the correctness of interface implementations. We defer it until this time to not require the interface and fields to be defined before the ‘implements` call.
Note that the GraphQL gem on its own supports a form of “interface inheritance”: if declaring that an object type implements an interface, and the object type is missing one or more of the interface fields, the GraphQL gem dynamically adds the missing interface fields to the object type (at least, that’s the result I noted when dumping the GraphQL SDL after trying that!). However, we cannot allow that, because our schema definition is used to generate non-GrapQL artifacts (e.g. the JSON schema and the index mapping), and all the artifacts must agree on the fields. Therefore, we use this method to verify that the object type fully implements the specified interfaces.
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 |
# File 'lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb', line 78 def verify_graphql_correctness! = implemented_interfaces.filter_map do |interface_ref| interface = interface_ref.resolved case interface when SchemaElements::InterfaceType differences = (_ = interface).interface_fields_by_name.values.filter_map do |interface_field| my_field_sdl = graphql_fields_by_name[interface_field.name]&.to_sdl(type_structure_only: true) interface_field_sdl = interface_field.to_sdl(type_structure_only: true) if my_field_sdl.nil? "missing `#{interface_field.name}`" elsif my_field_sdl != interface_field_sdl "`#{interface_field_sdl.strip}` vs `#{my_field_sdl.strip}`" end end unless differences.empty? "Type `#{name}` does not correctly implement interface `#{interface_ref}` " \ "due to field differences: #{differences.join("; ")}." end when nil "Type `#{name}` cannot implement `#{interface_ref}` because `#{interface_ref}` is not defined." else "Type `#{name}` cannot implement `#{interface_ref}` because `#{interface_ref}` is not an interface." end end unless .empty? raise Errors::SchemaError, .join("\n\n") end end |