elasticgraph-schema_definition 0.18.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +7 -0
- data/elasticgraph-schema_definition.gemspec +26 -0
- data/lib/elastic_graph/schema_definition/api.rb +359 -0
- data/lib/elastic_graph/schema_definition/factory.rb +506 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb +79 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb +59 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb +99 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb +62 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb +346 -0
- data/lib/elastic_graph/schema_definition/indexing/event_envelope.rb +74 -0
- data/lib/elastic_graph/schema_definition/indexing/field.rb +181 -0
- data/lib/elastic_graph/schema_definition/indexing/field_reference.rb +51 -0
- data/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb +65 -0
- data/lib/elastic_graph/schema_definition/indexing/field_type/object.rb +113 -0
- data/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb +51 -0
- data/lib/elastic_graph/schema_definition/indexing/field_type/union.rb +70 -0
- data/lib/elastic_graph/schema_definition/indexing/index.rb +318 -0
- data/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb +34 -0
- data/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb +234 -0
- data/lib/elastic_graph/schema_definition/indexing/list_counts_mapping.rb +53 -0
- data/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb +96 -0
- data/lib/elastic_graph/schema_definition/indexing/rollover_config.rb +25 -0
- data/lib/elastic_graph/schema_definition/indexing/update_target_factory.rb +54 -0
- data/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb +195 -0
- data/lib/elastic_graph/schema_definition/json_schema_pruner.rb +61 -0
- data/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb +31 -0
- data/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb +119 -0
- data/lib/elastic_graph/schema_definition/mixins/has_directives.rb +65 -0
- data/lib/elastic_graph/schema_definition/mixins/has_documentation.rb +74 -0
- data/lib/elastic_graph/schema_definition/mixins/has_indices.rb +281 -0
- data/lib/elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect.rb +46 -0
- data/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb +116 -0
- data/lib/elastic_graph/schema_definition/mixins/has_type_info.rb +181 -0
- data/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb +122 -0
- data/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb +47 -0
- data/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb +267 -0
- data/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb +38 -0
- data/lib/elastic_graph/schema_definition/rake_tasks.rb +190 -0
- data/lib/elastic_graph/schema_definition/results.rb +404 -0
- data/lib/elastic_graph/schema_definition/schema_artifact_manager.rb +482 -0
- data/lib/elastic_graph/schema_definition/schema_elements/argument.rb +56 -0
- data/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb +1541 -0
- data/lib/elastic_graph/schema_definition/schema_elements/deprecated_element.rb +21 -0
- data/lib/elastic_graph/schema_definition/schema_elements/directive.rb +40 -0
- data/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb +189 -0
- data/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb +73 -0
- data/lib/elastic_graph/schema_definition/schema_elements/enum_value_namer.rb +89 -0
- data/lib/elastic_graph/schema_definition/schema_elements/enums_for_indexed_types.rb +82 -0
- data/lib/elastic_graph/schema_definition/schema_elements/field.rb +1085 -0
- data/lib/elastic_graph/schema_definition/schema_elements/field_path.rb +112 -0
- data/lib/elastic_graph/schema_definition/schema_elements/field_source.rb +16 -0
- data/lib/elastic_graph/schema_definition/schema_elements/graphql_sdl_enumerator.rb +113 -0
- data/lib/elastic_graph/schema_definition/schema_elements/input_field.rb +31 -0
- data/lib/elastic_graph/schema_definition/schema_elements/input_type.rb +60 -0
- data/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb +72 -0
- data/lib/elastic_graph/schema_definition/schema_elements/list_counts_state.rb +40 -0
- data/lib/elastic_graph/schema_definition/schema_elements/object_type.rb +53 -0
- data/lib/elastic_graph/schema_definition/schema_elements/relationship.rb +218 -0
- data/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb +310 -0
- data/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb +36 -0
- data/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.rb +66 -0
- data/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb +237 -0
- data/lib/elastic_graph/schema_definition/schema_elements/type_reference.rb +353 -0
- data/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb +579 -0
- data/lib/elastic_graph/schema_definition/schema_elements/union_type.rb +157 -0
- data/lib/elastic_graph/schema_definition/scripting/file_system_repository.rb +77 -0
- data/lib/elastic_graph/schema_definition/scripting/script.rb +48 -0
- data/lib/elastic_graph/schema_definition/scripting/scripts/field/as_day_of_week.painless +24 -0
- data/lib/elastic_graph/schema_definition/scripting/scripts/field/as_time_of_day.painless +41 -0
- data/lib/elastic_graph/schema_definition/scripting/scripts/filter/by_time_of_day.painless +22 -0
- data/lib/elastic_graph/schema_definition/scripting/scripts/update/index_data.painless +93 -0
- data/lib/elastic_graph/schema_definition/state.rb +212 -0
- data/lib/elastic_graph/schema_definition/test_support.rb +113 -0
- metadata +513 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
module ElasticGraph
|
10
|
+
module SchemaDefinition
|
11
|
+
module SchemaElements
|
12
|
+
# Represents a potentially nested path to a field.
|
13
|
+
#
|
14
|
+
# @private
|
15
|
+
class FieldPath < Data.define(:first_part, :last_part, :path_parts)
|
16
|
+
# The type of the field (based purely on the last part; the parent parts aren't interesting here).
|
17
|
+
def type
|
18
|
+
last_part.type
|
19
|
+
end
|
20
|
+
|
21
|
+
def path
|
22
|
+
path_parts.map(&:name).join(".")
|
23
|
+
end
|
24
|
+
|
25
|
+
# The full path to the field in the index.
|
26
|
+
def path_in_index
|
27
|
+
path_parts.map(&:name_in_index).join(".")
|
28
|
+
end
|
29
|
+
|
30
|
+
# The full name of the field path, including the parent type name, such as "Widget.nested.some_field".
|
31
|
+
def fully_qualified_path
|
32
|
+
"#{first_part.parent_type.name}.#{path}"
|
33
|
+
end
|
34
|
+
|
35
|
+
# The full name of the field path in the index, including the parent type name, such as "Widget.nested.some_field".
|
36
|
+
def fully_qualified_path_in_index
|
37
|
+
"#{first_part.parent_type.name}.#{path_in_index}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# The full description of the field path, including the parent type name, and field type,
|
41
|
+
# such as "Widget.nested.some_field: ID".
|
42
|
+
def full_description
|
43
|
+
"#{fully_qualified_path}: #{type.name}"
|
44
|
+
end
|
45
|
+
|
46
|
+
# We hide `new` because `FieldPath` is only intended to be instantiated from a `Resolver` instance.
|
47
|
+
# Importantly, `Resolver` provides an invariant that we want: a `FieldPath` is never instantiated
|
48
|
+
# with an empty list of path parts. (This is important for the steep type checking, so it can count
|
49
|
+
# on `last_part` being non-nil).
|
50
|
+
private_class_method :new
|
51
|
+
|
52
|
+
# Responsible for resolving a particular field path (given as a string) into a `FieldPath` object.
|
53
|
+
#
|
54
|
+
# Important: this class optimizes performance by memoizing some things based on the current state
|
55
|
+
# of the ElasticGraph schema. It's intended to be used AFTER the schema is fully defined (e.g.
|
56
|
+
# as part of dumping schema artifacts). Using it before the schema has fully been defined requires
|
57
|
+
# that you discard the instance after using it, as it won't be aware of additions to the schema
|
58
|
+
# and may yield inaccurate results.
|
59
|
+
class Resolver
|
60
|
+
def initialize
|
61
|
+
@indexing_fields_by_public_name_by_type = ::Hash.new do |hash, type|
|
62
|
+
hash[type] = type
|
63
|
+
.indexing_fields_by_name_in_index
|
64
|
+
.values
|
65
|
+
.to_h { |f| [f.name, f] }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Resolves the given `path_string` relative to the given `type`.
|
70
|
+
# Returns `nil` if no field at that path can be found.
|
71
|
+
#
|
72
|
+
# Requires a block which will be called to determine if a parent field is valid to resolve through.
|
73
|
+
# For example, the caller may want to disallow all parent list fields, or disallow `nested` parent
|
74
|
+
# list fields while allowing `object` parent list fields.
|
75
|
+
def resolve_public_path(type, path_string)
|
76
|
+
field = nil # : Field?
|
77
|
+
|
78
|
+
path_parts = path_string.split(".").map do |field_name|
|
79
|
+
return nil unless type
|
80
|
+
return nil if field && !yield(field)
|
81
|
+
return nil unless (field = @indexing_fields_by_public_name_by_type.dig(type, field_name))
|
82
|
+
type = field.type.unwrap_list.as_object_type
|
83
|
+
field
|
84
|
+
end
|
85
|
+
|
86
|
+
return nil if path_parts.empty?
|
87
|
+
|
88
|
+
FieldPath.send(:new, path_parts.first, path_parts.last, path_parts)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Determines the nested paths in the given `path_string`
|
92
|
+
# Returns `nil` if no field at that path can be found, and
|
93
|
+
# returns `[]` if no nested paths are found.
|
94
|
+
#
|
95
|
+
# Nested paths are represented as the full path to the nested fields
|
96
|
+
# For example: a `path_string` of "foo.bar.baz" might have
|
97
|
+
# nested paths ["foo", "foo.bar.baz"]
|
98
|
+
def determine_nested_paths(type, path_string)
|
99
|
+
field_path = resolve_public_path(type, path_string) { true }
|
100
|
+
return nil unless field_path
|
101
|
+
|
102
|
+
parts_so_far = [] # : ::Array[::String]
|
103
|
+
field_path.path_parts.filter_map do |field|
|
104
|
+
parts_so_far << field.name
|
105
|
+
parts_so_far.join(".") if field.nested?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
module ElasticGraph
|
10
|
+
module SchemaDefinition
|
11
|
+
module SchemaElements
|
12
|
+
# @private
|
13
|
+
FieldSource = ::Data.define(:relationship_name, :field_path)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
module ElasticGraph
|
10
|
+
module SchemaDefinition
|
11
|
+
module SchemaElements
|
12
|
+
# Responsible for enumerating the SDL strings for all GraphQL types, both explicitly defined and derived.
|
13
|
+
#
|
14
|
+
# @private
|
15
|
+
class GraphQLSDLEnumerator
|
16
|
+
include ::Enumerable
|
17
|
+
# @dynamic schema_def_state
|
18
|
+
attr_reader :schema_def_state
|
19
|
+
|
20
|
+
def initialize(schema_def_state, all_types_except_root_query_type)
|
21
|
+
@schema_def_state = schema_def_state
|
22
|
+
@all_types_except_root_query_type = all_types_except_root_query_type
|
23
|
+
end
|
24
|
+
|
25
|
+
# Yields the SDL for each GraphQL type, including both explicitly defined
|
26
|
+
# GraphQL types and derived GraphqL types.
|
27
|
+
def each(&block)
|
28
|
+
all_types = enumerate_all_types.sort_by(&:name)
|
29
|
+
all_type_names = all_types.map(&:name).to_set
|
30
|
+
|
31
|
+
all_types.each do |type|
|
32
|
+
next if STOCK_GRAPHQL_SCALARS.include?(type.name)
|
33
|
+
yield type.to_sdl { |arg| all_type_names.include?(arg.value_type.fully_unwrapped.name) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def enumerate_all_types
|
40
|
+
[root_query_type].compact + @all_types_except_root_query_type
|
41
|
+
end
|
42
|
+
|
43
|
+
def aggregation_efficiency_hints_for(derived_indexed_types)
|
44
|
+
return nil if derived_indexed_types.empty?
|
45
|
+
|
46
|
+
hints = derived_indexed_types.map do |type|
|
47
|
+
derived_indexing_type = @schema_def_state.types_by_name.fetch(type.destination_type_ref.name)
|
48
|
+
alternate_field_name = (_ = derived_indexing_type).plural_root_query_field_name
|
49
|
+
grouping_field = type.id_source
|
50
|
+
|
51
|
+
" - The root `#{alternate_field_name}` field groups by `#{grouping_field}`"
|
52
|
+
end
|
53
|
+
|
54
|
+
<<~EOS
|
55
|
+
Note: aggregation queries are relatively expensive, and some fields have been pre-aggregated to allow
|
56
|
+
more efficient queries for some common aggregation cases:
|
57
|
+
|
58
|
+
#{hints.join("\n")}
|
59
|
+
EOS
|
60
|
+
end
|
61
|
+
|
62
|
+
def root_query_type
|
63
|
+
# Some of our tests need to define their own root `Query` type, so here we avoid
|
64
|
+
# generating `Query` if an sdl part exists that already defines it.
|
65
|
+
return nil if @schema_def_state.sdl_parts.flat_map { |sdl| sdl.lines }.any? { |line| line.start_with?("type Query") }
|
66
|
+
|
67
|
+
new_built_in_object_type "Query" do |t|
|
68
|
+
t.documentation "The query entry point for the entire schema."
|
69
|
+
|
70
|
+
@schema_def_state.types_by_name.values.select(&:indexed?).sort_by(&:name).each do |type|
|
71
|
+
# @type var indexed_type: Mixins::HasIndices & _Type
|
72
|
+
indexed_type = _ = type
|
73
|
+
|
74
|
+
t.relates_to_many(
|
75
|
+
indexed_type.plural_root_query_field_name,
|
76
|
+
indexed_type.name,
|
77
|
+
via: "ignore",
|
78
|
+
dir: :in,
|
79
|
+
singular: indexed_type.singular_root_query_field_name
|
80
|
+
) do |f|
|
81
|
+
f.documentation "Fetches `#{indexed_type.name}`s based on the provided arguments."
|
82
|
+
indexed_type.root_query_fields_customizations&.call(f)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Add additional efficiency hints to the aggregation field documentation if we have any such hints.
|
86
|
+
# This needs to be outside the `relates_to_many` block because `relates_to_many` adds its own "suffix" to
|
87
|
+
# the field documentation, and here we add another one.
|
88
|
+
if (agg_efficiency_hint = aggregation_efficiency_hints_for(indexed_type.derived_indexed_types))
|
89
|
+
agg_name = @schema_def_state.schema_elements.normalize_case("#{indexed_type.singular_root_query_field_name}_aggregations")
|
90
|
+
agg_field = t.graphql_fields_by_name.fetch(agg_name)
|
91
|
+
agg_field.documentation "#{agg_field.doc_comment}\n\n#{agg_efficiency_hint}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def new_built_in_object_type(name, &block)
|
98
|
+
new_object_type name do |type|
|
99
|
+
@schema_def_state.built_in_types_customization_blocks.each do |customization_block|
|
100
|
+
customization_block.call(type)
|
101
|
+
end
|
102
|
+
|
103
|
+
block.call(type)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def new_object_type(name, &block)
|
108
|
+
@schema_def_state.factory.new_object_type(name, &block)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "delegate"
|
10
|
+
require "elastic_graph/schema_definition/mixins/supports_default_value"
|
11
|
+
require "elastic_graph/schema_definition/schema_elements/field"
|
12
|
+
|
13
|
+
module ElasticGraph
|
14
|
+
module SchemaDefinition
|
15
|
+
module SchemaElements
|
16
|
+
# A decorator that wraps a `Field` in order to provide additional functionality that
|
17
|
+
# we need to support on fields on input types (but not on fields on return types).
|
18
|
+
#
|
19
|
+
# For example, fields on input types support default values, but return type fields do not.
|
20
|
+
#
|
21
|
+
# @private
|
22
|
+
class InputField < DelegateClass(Field)
|
23
|
+
prepend Mixins::SupportsDefaultValue
|
24
|
+
|
25
|
+
def to_sdl(type_structure_only: false, default_value_sdl: self.default_value_sdl, &arg_selector)
|
26
|
+
super(type_structure_only: type_structure_only, default_value_sdl: default_value_sdl, &arg_selector)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "delegate"
|
10
|
+
require "elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect"
|
11
|
+
require "elastic_graph/schema_definition/schema_elements/type_with_subfields"
|
12
|
+
|
13
|
+
module ElasticGraph
|
14
|
+
module SchemaDefinition
|
15
|
+
module SchemaElements
|
16
|
+
# Represents a GraphQL `input` (used primarily for filtering).
|
17
|
+
#
|
18
|
+
# @private
|
19
|
+
class InputType < DelegateClass(TypeWithSubfields)
|
20
|
+
include Mixins::HasReadableToSAndInspect.new { |t| t.name }
|
21
|
+
|
22
|
+
def initialize(schema_def_state, name)
|
23
|
+
schema_def_state.factory.new_type_with_subfields(
|
24
|
+
:input, name,
|
25
|
+
wrapping_type: self,
|
26
|
+
field_factory: schema_def_state.factory.method(:new_input_field)
|
27
|
+
) do |type|
|
28
|
+
# Here we clear `reserved_field_names` because those field names are reserved precisely for our usage
|
29
|
+
# here on input filters. If we don't set this to an empty set we'll get exceptions in `new_filter` above
|
30
|
+
# when we generate our standard filter operators.
|
31
|
+
#
|
32
|
+
# Note: we opt-out of the reserved field names here rather then opting in on the other `TypeWithSubfields`
|
33
|
+
# subtypes because this is the only case where we don't want the reserved field name check applied (but we
|
34
|
+
# have multiple subtypes where we do want it applied).
|
35
|
+
type.reserved_field_names = Set.new
|
36
|
+
|
37
|
+
super(type)
|
38
|
+
graphql_only true
|
39
|
+
yield self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def runtime_metadata(extra_update_targets)
|
44
|
+
SchemaArtifacts::RuntimeMetadata::ObjectType.new(
|
45
|
+
update_targets: extra_update_targets,
|
46
|
+
index_definition_names: [],
|
47
|
+
graphql_fields_by_name: graphql_fields_by_name.transform_values(&:runtime_metadata_graphql_field),
|
48
|
+
elasticgraph_category: nil,
|
49
|
+
source_type: nil,
|
50
|
+
graphql_only_return_type: false
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def derived_graphql_types
|
55
|
+
[]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "delegate"
|
10
|
+
require "elastic_graph/schema_definition/mixins/has_indices"
|
11
|
+
require "elastic_graph/schema_definition/mixins/has_subtypes"
|
12
|
+
require "elastic_graph/schema_definition/mixins/implements_interfaces"
|
13
|
+
require "elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation"
|
14
|
+
require "elastic_graph/schema_definition/schema_elements/type_with_subfields"
|
15
|
+
|
16
|
+
module ElasticGraph
|
17
|
+
module SchemaDefinition
|
18
|
+
module SchemaElements
|
19
|
+
# {include:API#interface_type}
|
20
|
+
#
|
21
|
+
# @example Define an interface
|
22
|
+
# ElasticGraph.define_schema do |schema|
|
23
|
+
# schema.interface_type "Athlete" do |t|
|
24
|
+
# # in the block, `t` is an InterfaceType
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
class InterfaceType < DelegateClass(TypeWithSubfields)
|
28
|
+
# As of the October 2021 GraphQL spec, interfaces can now implement other interfaces:
|
29
|
+
# http://spec.graphql.org/October2021/#sec-Interfaces.Interfaces-Implementing-Interfaces
|
30
|
+
# Originated from: graphql/graphql-spec#373
|
31
|
+
include Mixins::ImplementsInterfaces
|
32
|
+
include Mixins::SupportsFilteringAndAggregation
|
33
|
+
include Mixins::HasIndices
|
34
|
+
include Mixins::HasSubtypes
|
35
|
+
include Mixins::HasReadableToSAndInspect.new { |t| t.name }
|
36
|
+
|
37
|
+
# @private
|
38
|
+
def initialize(schema_def_state, name)
|
39
|
+
field_factory = schema_def_state.factory.method(:new_field)
|
40
|
+
schema_def_state.factory.new_type_with_subfields(:interface, name, wrapping_type: self, field_factory: field_factory) do |type|
|
41
|
+
__skip__ = super(type) do
|
42
|
+
yield self
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# This contains more than just the proper interface fields; it also contains the fields from the
|
48
|
+
# subtypes, which winds up being used to generate an input filter and aggregation type.
|
49
|
+
#
|
50
|
+
# For just the interface fields, use `interface_fields_by_name`.
|
51
|
+
#
|
52
|
+
# @private
|
53
|
+
def graphql_fields_by_name
|
54
|
+
merged_fields_from_subtypes_by_name = super # delegates to the `HasSubtypes` definition.
|
55
|
+
# The interface field definitions should take precedence over the merged fields from the subtypes.
|
56
|
+
merged_fields_from_subtypes_by_name.merge(interface_fields_by_name)
|
57
|
+
end
|
58
|
+
|
59
|
+
# @private
|
60
|
+
def interface_fields_by_name
|
61
|
+
__getobj__.graphql_fields_by_name
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def resolve_subtypes
|
67
|
+
schema_def_state.implementations_by_interface_ref[type_ref]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "elastic_graph/constants"
|
10
|
+
|
11
|
+
module ElasticGraph
|
12
|
+
module SchemaDefinition
|
13
|
+
module SchemaElements
|
14
|
+
# @private
|
15
|
+
class ListCountsState < ::Data.define(
|
16
|
+
# the path from the root to the current list counts field
|
17
|
+
:path_to_list_counts,
|
18
|
+
# the path within the list counts field
|
19
|
+
:path_from_list_counts
|
20
|
+
)
|
21
|
+
# @dynamic path_to_list_counts, path_from_list_counts, with
|
22
|
+
|
23
|
+
def self.new_list_counts_field(at:)
|
24
|
+
new(path_to_list_counts: at, path_from_list_counts: "")
|
25
|
+
end
|
26
|
+
|
27
|
+
INITIAL = new_list_counts_field(at: LIST_COUNTS_FIELD)
|
28
|
+
|
29
|
+
def [](subpath)
|
30
|
+
with(path_from_list_counts: "#{path_from_list_counts}#{subpath}.")
|
31
|
+
end
|
32
|
+
|
33
|
+
def path_to_count_subfield(subpath)
|
34
|
+
count_subfield = (path_from_list_counts + subpath).gsub(".", LIST_COUNTS_FIELD_PATH_KEY_SEPARATOR)
|
35
|
+
"#{path_to_list_counts}.#{count_subfield}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "delegate"
|
10
|
+
require "elastic_graph/error"
|
11
|
+
require "elastic_graph/schema_definition/mixins/has_indices"
|
12
|
+
require "elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect"
|
13
|
+
require "elastic_graph/schema_definition/mixins/implements_interfaces"
|
14
|
+
require "elastic_graph/schema_definition/schema_elements/type_with_subfields"
|
15
|
+
|
16
|
+
module ElasticGraph
|
17
|
+
module SchemaDefinition
|
18
|
+
module SchemaElements
|
19
|
+
# {include:API#object_type}
|
20
|
+
#
|
21
|
+
# @example Define an object type
|
22
|
+
# ElasticGraph.define_schema do |schema|
|
23
|
+
# schema.object_type "Money" do |t|
|
24
|
+
# # in the block, `t` is an ObjectType
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
class ObjectType < DelegateClass(TypeWithSubfields)
|
28
|
+
# DelegateClass(TypeWithSubfields) provides the following methods:
|
29
|
+
# @dynamic name, type_ref, to_sdl, derived_graphql_types, to_indexing_field_type, current_sources, index_field_runtime_metadata_tuples, graphql_only?, relay_pagination_type
|
30
|
+
include Mixins::SupportsFilteringAndAggregation
|
31
|
+
|
32
|
+
# `include HasIndices` provides the following methods:
|
33
|
+
# @dynamic runtime_metadata, derived_indexed_types, indices, indexed?, abstract?
|
34
|
+
include Mixins::HasIndices
|
35
|
+
|
36
|
+
# `include ImplementsInterfaces` provides the following methods:
|
37
|
+
# @dynamic verify_graphql_correctness!
|
38
|
+
include Mixins::ImplementsInterfaces
|
39
|
+
include Mixins::HasReadableToSAndInspect.new { |t| t.name }
|
40
|
+
|
41
|
+
# @private
|
42
|
+
def initialize(schema_def_state, name)
|
43
|
+
field_factory = schema_def_state.factory.method(:new_field)
|
44
|
+
schema_def_state.factory.new_type_with_subfields(:type, name, wrapping_type: self, field_factory: field_factory) do |type|
|
45
|
+
__skip__ = super(type) do
|
46
|
+
yield self
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|