elasticgraph-schema_definition 0.19.1.1 → 0.19.2.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/lib/elastic_graph/schema_definition/api.rb +111 -6
  4. data/lib/elastic_graph/schema_definition/factory.rb +25 -23
  5. data/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb +1 -1
  6. data/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb +1 -1
  7. data/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb +1 -1
  8. data/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb +1 -1
  9. data/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb +1 -1
  10. data/lib/elastic_graph/schema_definition/indexing/event_envelope.rb +12 -3
  11. data/lib/elastic_graph/schema_definition/indexing/field.rb +1 -1
  12. data/lib/elastic_graph/schema_definition/indexing/field_reference.rb +1 -1
  13. data/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb +1 -1
  14. data/lib/elastic_graph/schema_definition/indexing/field_type/object.rb +1 -1
  15. data/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb +1 -1
  16. data/lib/elastic_graph/schema_definition/indexing/field_type/union.rb +1 -1
  17. data/lib/elastic_graph/schema_definition/indexing/index.rb +4 -2
  18. data/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb +1 -1
  19. data/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb +1 -1
  20. data/lib/elastic_graph/schema_definition/indexing/list_counts_mapping.rb +1 -1
  21. data/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb +1 -1
  22. data/lib/elastic_graph/schema_definition/indexing/rollover_config.rb +1 -1
  23. data/lib/elastic_graph/schema_definition/indexing/update_target_factory.rb +1 -1
  24. data/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb +1 -1
  25. data/lib/elastic_graph/schema_definition/json_schema_pruner.rb +4 -2
  26. data/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb +1 -1
  27. data/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb +1 -1
  28. data/lib/elastic_graph/schema_definition/mixins/has_directives.rb +1 -1
  29. data/lib/elastic_graph/schema_definition/mixins/has_documentation.rb +1 -1
  30. data/lib/elastic_graph/schema_definition/mixins/has_indices.rb +40 -4
  31. data/lib/elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect.rb +2 -1
  32. data/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb +1 -1
  33. data/lib/elastic_graph/schema_definition/mixins/has_type_info.rb +1 -1
  34. data/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb +1 -1
  35. data/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb +1 -1
  36. data/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb +9 -3
  37. data/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb +1 -1
  38. data/lib/elastic_graph/schema_definition/rake_tasks.rb +1 -1
  39. data/lib/elastic_graph/schema_definition/results.rb +133 -13
  40. data/lib/elastic_graph/schema_definition/schema_artifact_manager.rb +4 -4
  41. data/lib/elastic_graph/schema_definition/schema_elements/argument.rb +1 -1
  42. data/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb +47 -15
  43. data/lib/elastic_graph/schema_definition/schema_elements/deprecated_element.rb +1 -1
  44. data/lib/elastic_graph/schema_definition/schema_elements/directive.rb +1 -1
  45. data/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb +1 -1
  46. data/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb +1 -1
  47. data/lib/elastic_graph/schema_definition/schema_elements/enum_value_namer.rb +1 -1
  48. data/lib/elastic_graph/schema_definition/schema_elements/enums_for_indexed_types.rb +1 -1
  49. data/lib/elastic_graph/schema_definition/schema_elements/field.rb +15 -10
  50. data/lib/elastic_graph/schema_definition/schema_elements/field_path.rb +1 -1
  51. data/lib/elastic_graph/schema_definition/schema_elements/field_source.rb +1 -1
  52. data/lib/elastic_graph/schema_definition/schema_elements/graphql_sdl_enumerator.rb +4 -78
  53. data/lib/elastic_graph/schema_definition/schema_elements/input_field.rb +1 -1
  54. data/lib/elastic_graph/schema_definition/schema_elements/input_type.rb +6 -2
  55. data/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb +1 -1
  56. data/lib/elastic_graph/schema_definition/schema_elements/list_counts_state.rb +1 -1
  57. data/lib/elastic_graph/schema_definition/schema_elements/object_type.rb +1 -1
  58. data/lib/elastic_graph/schema_definition/schema_elements/relationship.rb +8 -2
  59. data/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb +3 -3
  60. data/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb +1 -1
  61. data/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.rb +1 -1
  62. data/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb +1 -1
  63. data/lib/elastic_graph/schema_definition/schema_elements/type_reference.rb +1 -1
  64. data/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb +4 -5
  65. data/lib/elastic_graph/schema_definition/schema_elements/union_type.rb +1 -1
  66. data/lib/elastic_graph/schema_definition/scripting/file_system_repository.rb +1 -1
  67. data/lib/elastic_graph/schema_definition/scripting/script.rb +1 -1
  68. data/lib/elastic_graph/schema_definition/state.rb +4 -1
  69. data/lib/elastic_graph/schema_definition/test_support.rb +23 -3
  70. metadata +32 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 534927a4b62a7b84a341e47407841b593497ee8399f6413ab0dd16db24eebde5
4
- data.tar.gz: c0c0081897e0086584fa326878a6b6e5dc3f92252297b1fa4f030882515b8718
3
+ metadata.gz: 22e12695336b4d4f8783be5181dfe89462829d9603709092c1748be483582d34
4
+ data.tar.gz: ad51712ce4e2c784c68472a9ca3d7708aeb12bc4394eb884d946335bad7353a8
5
5
  SHA512:
6
- metadata.gz: 9b95020047583aef5fa220bef18cff7c8e17ee13272c34ea89c1ffadf44db7ffb23d146de37c220b9f357e8202d7b6aa5b058551e82829d1448ac7d4e9e7ad44
7
- data.tar.gz: be19ced1f5be7199ade1fec2b139ebb26c0c3e5cf950ac875ea75b588818559ea5e9ce22ddadca578384ab54819f9cc6d4aa60f12438eb2cac2a40b8f1de1cef
6
+ metadata.gz: 922823d7384a8ff245530e51ccd465fcadf53d8a072b996fbc9417a520df031db98c5782ad416bcce233e3b0d2fec5584ce1840a6be39e9b87944d195f303e7f
7
+ data.tar.gz: 347c485375ea7dc41e2ee212fe155a1cbcf937008956b9387c78e97b97c02869057f103f23adc1a98f2a3c2972ac1fa09a34f61001d030c4c0fcb779c9a8282e
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024 Block, Inc.
3
+ Copyright (c) 2024 - 2025 Block, Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -8,6 +8,7 @@
8
8
 
9
9
  require "elastic_graph/errors"
10
10
  require "elastic_graph/schema_artifacts/runtime_metadata/extension"
11
+ require "elastic_graph/schema_artifacts/runtime_metadata/graphql_resolver"
11
12
  require "elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect"
12
13
  require "elastic_graph/schema_definition/results"
13
14
  require "elastic_graph/schema_definition/state"
@@ -130,7 +131,7 @@ module ElasticGraph
130
131
  nil
131
132
  end
132
133
 
133
- # Defines a [GraphQL interface](https://graphql.org/learn/schema/#interfaces). Use it to define an abstract supertype with
134
+ # Defines a [GraphQL interface](https://graphql.org/learn/schema/#interface-types). Use it to define an abstract supertype with
134
135
  # one or more fields that concrete implementations of the interface must also define. Each implementation can be an
135
136
  # {SchemaElements::ObjectType} or {SchemaElements::InterfaceType}.
136
137
  #
@@ -164,7 +165,7 @@ module ElasticGraph
164
165
  nil
165
166
  end
166
167
 
167
- # Defines a [GraphQL enum type](https://graphql.org/learn/schema/#enumeration-types).
168
+ # Defines a [GraphQL enum type](https://graphql.org/learn/schema/#enum-types).
168
169
  # The type is restricted to an enumerated set of values, each with a unique name.
169
170
  # Use `value` or `values` to define the enum values in the passed block.
170
171
  #
@@ -275,7 +276,7 @@ module ElasticGraph
275
276
  #
276
277
  # @param extension_module [Module] GraphQL extension module
277
278
  # @param defined_at [String] the `require` path of the extension module
278
- # @param extension_config [Hash<Symbol, Object>] configuration options for the extension module
279
+ # @param config [Hash<Symbol, Object>] configuration options for the extension module
279
280
  # @return [void]
280
281
  #
281
282
  # @example Register `elasticgraph-query_registry` extension module
@@ -285,8 +286,94 @@ module ElasticGraph
285
286
  # schema.register_graphql_extension ElasticGraph::QueryRegistry::GraphQLExtension,
286
287
  # defined_at: query_registry_require_path
287
288
  # end
288
- def register_graphql_extension(extension_module, defined_at:, **extension_config)
289
- @state.graphql_extension_modules << SchemaArtifacts::RuntimeMetadata::Extension.new(extension_module, defined_at, extension_config)
289
+ def register_graphql_extension(extension_module, defined_at:, **config)
290
+ @state.graphql_extension_modules << SchemaArtifacts::RuntimeMetadata::Extension.new(extension_module, defined_at, config)
291
+ nil
292
+ end
293
+
294
+ # Registers a GraphQL resolver that will be loaded and used by `elasticgraph-graphql`. To use a GraphQL resolver you have
295
+ # registered, set a field's `resolver` to the name you provide when registering your resolver.
296
+ #
297
+ # @param name [Symbol] unique name of the resolver
298
+ # @param klass [Class] resolver class
299
+ # @param defined_at [String] the `require` path of the resolver
300
+ # @param resolver_config [Hash<Symbol, Object>] configuration options for the resolver, to support parameterized resolvers
301
+ # @return [void]
302
+ #
303
+ # @example Register a custom resolver for use by a custom `Query` field
304
+ # # In `add_resolver.rb`:
305
+ # class AddResolver
306
+ # def initialize(elasticgraph_graphql:, config:)
307
+ # end
308
+ #
309
+ # def resolve(field:, object:, args:, context:)
310
+ # args.fetch("x") + args.fetch("y")
311
+ # end
312
+ # end
313
+ #
314
+ # # In `config/schema.rb`:
315
+ # ElasticGraph.define_schema do |schema|
316
+ # require(resolver_path = "add_resolver")
317
+ # schema.register_graphql_resolver :add, AddResolver, defined_at: resolver_path
318
+ #
319
+ # schema.on_root_query_type do |t|
320
+ # t.field "add", "Int" do |f|
321
+ # f.argument "x", "Int!"
322
+ # f.argument "y", "Int!"
323
+ # f.resolver = :add
324
+ # end
325
+ # end
326
+ # end
327
+ #
328
+ # @example Register a custom resolver that uses lookahead
329
+ #
330
+ # # In `artist_resolver.rb`:
331
+ # class ArtistResolver
332
+ # def initialize(elasticgraph_graphql:, config:)
333
+ # end
334
+ #
335
+ # def resolve(field:, object:, args:, context:, lookahead:)
336
+ # # The extra `lookahead` argument can be used to see what child fields are selected.
337
+ # # See https://graphql-ruby.org/queries/lookahead.html for details.
338
+ # #
339
+ # # Note: there is overhead involved in providing the `lookahead`, so it's best to not
340
+ # # request it (by defining it as one of the `resolve` arguments) unless it's really needed.
341
+ # end
342
+ # end
343
+ #
344
+ # # In `config/schema.rb`:
345
+ # ElasticGraph.define_schema do |schema|
346
+ # require(resolver_path = "artist_resolver")
347
+ # schema.register_graphql_resolver :artist, ArtistResolver, defined_at: resolver_path
348
+ #
349
+ # schema.object_type "Artist" do |t|
350
+ # t.field "name", "String"
351
+ # # ...
352
+ # end
353
+ #
354
+ # schema.on_root_query_type do |t|
355
+ # t.field "artist", "Artist" do |f|
356
+ # f.resolver = :artist
357
+ # end
358
+ # end
359
+ # end
360
+ def register_graphql_resolver(name, klass, defined_at:, **resolver_config)
361
+ extension = SchemaArtifacts::RuntimeMetadata::Extension.new(klass, defined_at, resolver_config)
362
+
363
+ needs_lookahead =
364
+ if extension.verify_against(SchemaArtifacts::RuntimeMetadata::GraphQLResolver::InterfaceWithLookahead).empty?
365
+ true
366
+ else
367
+ extension.verify_against!(SchemaArtifacts::RuntimeMetadata::GraphQLResolver::InterfaceWithoutLookahead)
368
+ false
369
+ end
370
+
371
+ resolver = SchemaArtifacts::RuntimeMetadata::GraphQLResolver.new(
372
+ needs_lookahead: needs_lookahead,
373
+ resolver_ref: extension.to_dumpable_hash
374
+ )
375
+
376
+ @state.graphql_resolvers_by_name[name] = resolver
290
377
  nil
291
378
  end
292
379
 
@@ -343,6 +430,24 @@ module ElasticGraph
343
430
  nil
344
431
  end
345
432
 
433
+ # Registers a customization callback that will be applied to the root `Query` type when it is generated.
434
+ #
435
+ # @yield [SchemaElements::ObjectType] the root `Query` type
436
+ # @return [void]
437
+ #
438
+ # @example Customize documentation of built-in types
439
+ # ElasticGraph.define_schema do |schema|
440
+ # schema.on_root_query_type do |type|
441
+ # type.append_to_documentation "This schema has been generated by ElasticGraph."
442
+ # end
443
+ # end
444
+ def on_root_query_type(&customization_block)
445
+ on_built_in_types do |type|
446
+ customization_block.call(_ = type) if type.name == "Query"
447
+ end
448
+ nil
449
+ end
450
+
346
451
  # While the block executes, makes any `ElasticGraph.define_schema` calls operate on this `API` instance.
347
452
  #
348
453
  # @private
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -115,8 +115,8 @@ module ElasticGraph
115
115
  end
116
116
  @@field_new = prevent_non_factory_instantiation_of(SchemaElements::Field)
117
117
 
118
- def new_graphql_sdl_enumerator(all_types_except_root_query_type)
119
- @@graphql_sdl_enumerator_new.call(@state, all_types_except_root_query_type)
118
+ def new_graphql_sdl_enumerator(all_types)
119
+ @@graphql_sdl_enumerator_new.call(@state, all_types)
120
120
  end
121
121
  @@graphql_sdl_enumerator_new = prevent_non_factory_instantiation_of(SchemaElements::GraphQLSDLEnumerator)
122
122
 
@@ -137,6 +137,8 @@ module ElasticGraph
137
137
  @@input_type_new = prevent_non_factory_instantiation_of(SchemaElements::InputType)
138
138
 
139
139
  def new_filter_input_type(source_type, name_prefix: source_type, category: :filter_input)
140
+ all_of = @state.schema_elements.all_of
141
+ any_of = @state.schema_elements.any_of
140
142
  new_input_type(@state.type_ref(name_prefix).as_static_derived_type(category).name) do |t|
141
143
  t.documentation <<~EOS
142
144
  Input type used to specify filters on `#{source_type}` fields.
@@ -154,6 +156,18 @@ module ElasticGraph
154
156
  EOS
155
157
  end
156
158
 
159
+ t.field @state.schema_elements.all_of, "[#{t.name}!]" do |f|
160
+ f.documentation <<~EOS
161
+ Matches records where all of the provided sub-filters evaluate to true. This works just like an AND operator in SQL.
162
+
163
+ Note: multiple filters are automatically ANDed together. This is only needed when you have multiple filters that can't
164
+ be provided on a single `#{t.name}` input because of collisions between key names. For example, if you want to AND multiple
165
+ OR'd sub-filters (the equivalent of (A OR B) AND (C OR D)), you could do #{all_of}: [{#{any_of}: [...]}, {#{any_of}: [...]}].
166
+
167
+ When `null` or an empty list is passed, matches all documents.
168
+ EOS
169
+ end
170
+
157
171
  t.field @state.schema_elements.not, t.name do |f|
158
172
  f.documentation <<~EOS
159
173
  Matches records where the provided sub-filter evaluates to false.
@@ -272,7 +286,8 @@ module ElasticGraph
272
286
  new_object_type @state.type_ref(index_leaf_type).as_aggregated_values.name do |type|
273
287
  type.graphql_only true
274
288
  type.documentation "A return type used from aggregations to provided aggregated values over `#{index_leaf_type}` fields."
275
- type.runtime_metadata_overrides = {elasticgraph_category: :scalar_aggregated_values}
289
+ type.default_graphql_resolver = :object_with_lookahead
290
+ type.override_runtime_metadata(elasticgraph_category: :scalar_aggregated_values)
276
291
 
277
292
  type.field @state.schema_elements.approximate_distinct_value_count, "JsonSafeLong", graphql_only: true do |f|
278
293
  # Note: the 1-6% accuracy figure comes from the Elasticsearch docs:
@@ -296,7 +311,6 @@ module ElasticGraph
296
311
 
297
312
  def new_list_filter_input_type(source_type, name_prefix:, any_satisfy_type_category:)
298
313
  any_satisfy = @state.schema_elements.any_satisfy
299
- all_of = @state.schema_elements.all_of
300
314
 
301
315
  new_filter_input_type "[#{source_type}]", name_prefix: name_prefix, category: :list_filter_input do |t|
302
316
  t.field any_satisfy, @state.type_ref(name_prefix).as_static_derived_type(any_satisfy_type_category).name do |f|
@@ -307,18 +321,6 @@ module ElasticGraph
307
321
  EOS
308
322
  end
309
323
 
310
- t.field all_of, "[#{t.name}!]" do |f|
311
- f.documentation <<~EOS
312
- Matches records where all of the provided sub-filters evaluate to true. This works just like an AND operator in SQL.
313
-
314
- Note: multiple filters are automatically ANDed together. This is only needed when you have multiple filters that can't
315
- be provided on a single `#{t.name}` input because of collisions between key names. For example, if you want to provide
316
- multiple `#{any_satisfy}: ...` filters, you could do `#{all_of}: [{#{any_satisfy}: ...}, {#{any_satisfy}: ...}]`.
317
-
318
- When `null` or an empty list is passed, matches all documents.
319
- EOS
320
- end
321
-
322
324
  define_list_counts_filter_field_on(t)
323
325
  end
324
326
  end
@@ -433,7 +435,8 @@ module ElasticGraph
433
435
  type_ref = @state.type_ref(type_name)
434
436
  new_object_type type_ref.as_edge.name do |t|
435
437
  t.relay_pagination_type = true
436
- t.runtime_metadata_overrides = {elasticgraph_category: :relay_edge}
438
+ t.default_graphql_resolver = :object_without_lookahead
439
+ t.override_runtime_metadata(elasticgraph_category: :relay_edge)
437
440
 
438
441
  t.documentation <<~EOS
439
442
  Represents a specific `#{type_name}` in the context of a `#{type_ref.as_connection.name}`,
@@ -460,7 +463,8 @@ module ElasticGraph
460
463
  type_ref = @state.type_ref(type_name)
461
464
  new_object_type type_ref.as_connection.name do |t|
462
465
  t.relay_pagination_type = true
463
- t.runtime_metadata_overrides = {elasticgraph_category: :relay_connection}
466
+ t.default_graphql_resolver = :object_without_lookahead
467
+ t.override_runtime_metadata(elasticgraph_category: :relay_connection)
464
468
 
465
469
  if support_pagination
466
470
  t.documentation <<~EOS
@@ -483,10 +487,8 @@ module ElasticGraph
483
487
  f.documentation "The list of `#{type_name}` results."
484
488
  end
485
489
 
486
- if support_pagination
487
- t.field @state.schema_elements.page_info, "PageInfo!" do |f|
488
- f.documentation "Provides pagination-related information."
489
- end
490
+ t.field @state.schema_elements.page_info, "PageInfo!" do |f|
491
+ f.documentation "Provides pagination-related information."
490
492
  end
491
493
 
492
494
  if include_total_edge_count
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -21,41 +21,50 @@ module ElasticGraph
21
21
  def self.json_schema(indexed_type_names, json_schema_version)
22
22
  {
23
23
  "type" => "object",
24
+ "description" => "Required by ElasticGraph to wrap every data event.",
24
25
  "properties" => {
25
26
  "op" => {
27
+ "description" => "Indicates what type of operation the event represents. For now, only `upsert` is supported, but we plan to support other operations in the future.",
26
28
  "type" => "string",
27
29
  "enum" => %w[upsert]
28
30
  },
29
31
  "type" => {
32
+ "description" => "The type of object present in `record`.",
30
33
  "type" => "string",
31
34
  # Sorting doesn't really matter here, but it's nice for the output in the schema artifact to be consistent.
32
35
  "enum" => indexed_type_names.sort
33
36
  },
34
37
  "id" => {
38
+ "description" => "The unique identifier of the record.",
35
39
  "type" => "string",
36
40
  "maxLength" => DEFAULT_MAX_KEYWORD_LENGTH
37
41
  },
38
42
  "version" => {
43
+ "description" => 'Used to handle duplicate and out-of-order events. When ElasticGraph ingests multiple events for the same `type` and `id`, the one with the largest `version` will "win".',
39
44
  "type" => "integer",
40
45
  "minimum" => 0,
41
46
  "maximum" => (2**63) - 1
42
47
  },
43
48
  "record" => {
49
+ "description" => "The record of this event. The payload of this field must match the JSON schema of the named `type`.",
44
50
  "type" => "object"
45
51
  },
46
52
  "latency_timestamps" => {
53
+ "description" => "Timestamps from which ElasticGraph measures indexing latency. The `ElasticGraphIndexingLatencies` log message produced for each event will include a measurement from each timestamp included in this map.",
47
54
  "type" => "object",
48
55
  "additionalProperties" => false,
49
56
  "patternProperties" => {
57
+ "description" => "A timestamp from which ElasticGraph will measure indexing latency. The timestamp name must end in `_at`.",
50
58
  "^\\w+_at$" => {"type" => "string", "format" => "date-time"}
51
59
  }
52
60
  },
53
61
  JSON_SCHEMA_VERSION_KEY => {
62
+ "description" => "The version of the JSON schema the publisher was using when the event was published. ElasticGraph will use the JSON schema matching this version to process the event.",
54
63
  "const" => json_schema_version
55
64
  },
56
65
  "message_id" => {
57
- "type" => "string",
58
- "description" => "The optional ID of the message containing this event from whatever messaging system is being used between the publisher and the ElasticGraph indexer."
66
+ "description" => "The optional ID of the message containing this event from whatever messaging system is being used between the publisher and the ElasticGraph indexer.",
67
+ "type" => "string"
59
68
  }
60
69
  },
61
70
  "additionalProperties" => false,
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -248,7 +248,9 @@ module ElasticGraph
248
248
  "index.mapping.ignore_malformed" => false,
249
249
  "index.mapping.coerce" => false,
250
250
  "index.number_of_replicas" => 1,
251
- "index.number_of_shards" => 1
251
+ "index.number_of_shards" => 1,
252
+ # 10K is the default: https://www.elastic.co/guide/en/elasticsearch/reference/8.17/index-modules.html#dynamic-index-settings
253
+ "index.max_result_window" => 10000
252
254
  }
253
255
 
254
256
  def mappings
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -21,7 +21,9 @@ module ElasticGraph
21
21
  types_to_keep = referenced_type_names(initial_type_names, original_json_schema["$defs"])
22
22
 
23
23
  # The .select will preserve the sort order of the original hash
24
+ # standard:disable Style/HashSlice -- https://github.com/soutaro/steep/issues/1503
24
25
  pruned_defs = original_json_schema["$defs"].select { |k, _v| types_to_keep.include?(k) }
26
+ # standard:enable Style/HashSlice
25
27
 
26
28
  original_json_schema.merge("$defs" => pruned_defs)
27
29
  end
@@ -31,7 +33,7 @@ module ElasticGraph
31
33
  def self.referenced_type_names(source_type_names, original_defs)
32
34
  return Set.new if source_type_names.empty?
33
35
 
34
- referenced_type_defs = original_defs.select { |k, _| source_type_names.include?(k) }
36
+ referenced_type_defs = original_defs.slice(*source_type_names)
35
37
  ref_names = collect_ref_names(referenced_type_defs)
36
38
 
37
39
  referenced_type_names(ref_names, original_defs) + source_type_names
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -7,6 +7,7 @@
7
7
  # frozen_string_literal: true
8
8
 
9
9
  require "elastic_graph/constants"
10
+ require "elastic_graph/errors"
10
11
  require "elastic_graph/schema_definition/indexing/update_target_factory"
11
12
 
12
13
  module ElasticGraph
@@ -16,12 +17,17 @@ module ElasticGraph
16
17
  module HasIndices
17
18
  # @dynamic runtime_metadata_overrides
18
19
  # @private
19
- attr_accessor :runtime_metadata_overrides
20
+ attr_reader :runtime_metadata_overrides
21
+
22
+ # @return [::Symbol, nil] the default GraphQL resolver to use for fields on this type
23
+ attr_accessor :default_graphql_resolver
24
+ # @dynamic default_graphql_resolver, default_graphql_resolver=
20
25
 
21
26
  # @private
22
27
  def initialize(*args, **options)
23
28
  super(*args, **options)
24
- self.runtime_metadata_overrides = {}
29
+ @runtime_metadata_overrides = {}
30
+ self.default_graphql_resolver = :get_record_field_value
25
31
  yield self
26
32
 
27
33
  # Freeze `indices` so that the indexable status of a type does not change after instantiation.
@@ -150,6 +156,15 @@ module ElasticGraph
150
156
  @derived_indexed_types ||= []
151
157
  end
152
158
 
159
+ # Configures overrides for runtime metadata. The provided runtime metadata values will be persisted in the
160
+ # `runtime_metadata.yaml` schema artifact and made available at runtime to `elasticgraph-graphql` and
161
+ # `elasticgraph-indexer`.
162
+ #
163
+ # @return [void]
164
+ def override_runtime_metadata(**overrides)
165
+ @runtime_metadata_overrides.merge!(overrides)
166
+ end
167
+
153
168
  # @private
154
169
  def runtime_metadata(extra_update_targets)
155
170
  SchemaArtifacts::RuntimeMetadata::ObjectType.new(
@@ -255,7 +270,28 @@ module ElasticGraph
255
270
  end
256
271
 
257
272
  def runtime_metadata_graphql_fields_by_name
258
- graphql_fields_by_name.transform_values(&:runtime_metadata_graphql_field)
273
+ graphql_fields_by_name.transform_values do |field|
274
+ field_metadata = field.runtime_metadata_graphql_field
275
+
276
+ if field_metadata.resolver.nil?
277
+ if default_graphql_resolver
278
+ field_metadata.with(resolver: default_graphql_resolver)
279
+ else
280
+ parent_type_option =
281
+ if name == "Query"
282
+ # With `Query`, we don't want to use the `default_graphql_resolver`. Each field should set its own resolver.
283
+ ""
284
+ else
285
+ "the `default_graphql_resolver` on the parent type (`#{name}`) or "
286
+ end
287
+
288
+ raise Errors::SchemaError, "`#{name}.#{field.name}` needs a resolver. Fix by assigning #{parent_type_option}" \
289
+ "a `resolver` on the field (`#{field.name}`)."
290
+ end
291
+ else
292
+ field_metadata
293
+ end
294
+ end
259
295
  end
260
296
 
261
297
  # Provides a "best effort" conversion of a type name to the plural form.
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -29,6 +29,7 @@ module ElasticGraph
29
29
  def initialize
30
30
  if block_given?
31
31
  define_method :to_s do
32
+ # @type self: HasReadableToSAndInspect
32
33
  "#<#{self.class.name} #{yield self}>"
33
34
  end
34
35
  else