elasticgraph-schema_definition 0.18.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +7 -0
  4. data/elasticgraph-schema_definition.gemspec +26 -0
  5. data/lib/elastic_graph/schema_definition/api.rb +359 -0
  6. data/lib/elastic_graph/schema_definition/factory.rb +506 -0
  7. data/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb +79 -0
  8. data/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb +59 -0
  9. data/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb +99 -0
  10. data/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb +62 -0
  11. data/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb +346 -0
  12. data/lib/elastic_graph/schema_definition/indexing/event_envelope.rb +74 -0
  13. data/lib/elastic_graph/schema_definition/indexing/field.rb +181 -0
  14. data/lib/elastic_graph/schema_definition/indexing/field_reference.rb +51 -0
  15. data/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb +65 -0
  16. data/lib/elastic_graph/schema_definition/indexing/field_type/object.rb +113 -0
  17. data/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb +51 -0
  18. data/lib/elastic_graph/schema_definition/indexing/field_type/union.rb +70 -0
  19. data/lib/elastic_graph/schema_definition/indexing/index.rb +318 -0
  20. data/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb +34 -0
  21. data/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb +234 -0
  22. data/lib/elastic_graph/schema_definition/indexing/list_counts_mapping.rb +53 -0
  23. data/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb +96 -0
  24. data/lib/elastic_graph/schema_definition/indexing/rollover_config.rb +25 -0
  25. data/lib/elastic_graph/schema_definition/indexing/update_target_factory.rb +54 -0
  26. data/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb +195 -0
  27. data/lib/elastic_graph/schema_definition/json_schema_pruner.rb +61 -0
  28. data/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb +31 -0
  29. data/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb +119 -0
  30. data/lib/elastic_graph/schema_definition/mixins/has_directives.rb +65 -0
  31. data/lib/elastic_graph/schema_definition/mixins/has_documentation.rb +74 -0
  32. data/lib/elastic_graph/schema_definition/mixins/has_indices.rb +281 -0
  33. data/lib/elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect.rb +46 -0
  34. data/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb +116 -0
  35. data/lib/elastic_graph/schema_definition/mixins/has_type_info.rb +181 -0
  36. data/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb +122 -0
  37. data/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb +47 -0
  38. data/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb +267 -0
  39. data/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb +38 -0
  40. data/lib/elastic_graph/schema_definition/rake_tasks.rb +190 -0
  41. data/lib/elastic_graph/schema_definition/results.rb +404 -0
  42. data/lib/elastic_graph/schema_definition/schema_artifact_manager.rb +482 -0
  43. data/lib/elastic_graph/schema_definition/schema_elements/argument.rb +56 -0
  44. data/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb +1541 -0
  45. data/lib/elastic_graph/schema_definition/schema_elements/deprecated_element.rb +21 -0
  46. data/lib/elastic_graph/schema_definition/schema_elements/directive.rb +40 -0
  47. data/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb +189 -0
  48. data/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb +73 -0
  49. data/lib/elastic_graph/schema_definition/schema_elements/enum_value_namer.rb +89 -0
  50. data/lib/elastic_graph/schema_definition/schema_elements/enums_for_indexed_types.rb +82 -0
  51. data/lib/elastic_graph/schema_definition/schema_elements/field.rb +1085 -0
  52. data/lib/elastic_graph/schema_definition/schema_elements/field_path.rb +112 -0
  53. data/lib/elastic_graph/schema_definition/schema_elements/field_source.rb +16 -0
  54. data/lib/elastic_graph/schema_definition/schema_elements/graphql_sdl_enumerator.rb +113 -0
  55. data/lib/elastic_graph/schema_definition/schema_elements/input_field.rb +31 -0
  56. data/lib/elastic_graph/schema_definition/schema_elements/input_type.rb +60 -0
  57. data/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb +72 -0
  58. data/lib/elastic_graph/schema_definition/schema_elements/list_counts_state.rb +40 -0
  59. data/lib/elastic_graph/schema_definition/schema_elements/object_type.rb +53 -0
  60. data/lib/elastic_graph/schema_definition/schema_elements/relationship.rb +218 -0
  61. data/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb +310 -0
  62. data/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb +36 -0
  63. data/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.rb +66 -0
  64. data/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb +237 -0
  65. data/lib/elastic_graph/schema_definition/schema_elements/type_reference.rb +353 -0
  66. data/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb +579 -0
  67. data/lib/elastic_graph/schema_definition/schema_elements/union_type.rb +157 -0
  68. data/lib/elastic_graph/schema_definition/scripting/file_system_repository.rb +77 -0
  69. data/lib/elastic_graph/schema_definition/scripting/script.rb +48 -0
  70. data/lib/elastic_graph/schema_definition/scripting/scripts/field/as_day_of_week.painless +24 -0
  71. data/lib/elastic_graph/schema_definition/scripting/scripts/field/as_time_of_day.painless +41 -0
  72. data/lib/elastic_graph/schema_definition/scripting/scripts/filter/by_time_of_day.painless +22 -0
  73. data/lib/elastic_graph/schema_definition/scripting/scripts/update/index_data.painless +93 -0
  74. data/lib/elastic_graph/schema_definition/state.rb +212 -0
  75. data/lib/elastic_graph/schema_definition/test_support.rb +113 -0
  76. 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