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.
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