elasticgraph-schema_definition 0.19.1.0 → 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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/lib/elastic_graph/schema_definition/api.rb +111 -6
- data/lib/elastic_graph/schema_definition/factory.rb +25 -23
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/event_envelope.rb +12 -3
- data/lib/elastic_graph/schema_definition/indexing/field.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/field_reference.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/field_type/object.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/field_type/union.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/index.rb +4 -2
- data/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/list_counts_mapping.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/rollover_config.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/update_target_factory.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb +1 -1
- data/lib/elastic_graph/schema_definition/json_schema_pruner.rb +4 -2
- data/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_directives.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_documentation.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_indices.rb +40 -4
- data/lib/elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect.rb +2 -1
- data/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_type_info.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb +9 -3
- data/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb +1 -1
- data/lib/elastic_graph/schema_definition/rake_tasks.rb +1 -1
- data/lib/elastic_graph/schema_definition/results.rb +133 -13
- data/lib/elastic_graph/schema_definition/schema_artifact_manager.rb +4 -4
- data/lib/elastic_graph/schema_definition/schema_elements/argument.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb +47 -15
- data/lib/elastic_graph/schema_definition/schema_elements/deprecated_element.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/directive.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/enum_value_namer.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/enums_for_indexed_types.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/field.rb +15 -10
- data/lib/elastic_graph/schema_definition/schema_elements/field_path.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/field_source.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/graphql_sdl_enumerator.rb +4 -78
- data/lib/elastic_graph/schema_definition/schema_elements/input_field.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/input_type.rb +6 -2
- data/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/list_counts_state.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/object_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/relationship.rb +8 -2
- data/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb +3 -3
- data/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/type_reference.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb +4 -5
- data/lib/elastic_graph/schema_definition/schema_elements/union_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/scripting/file_system_repository.rb +1 -1
- data/lib/elastic_graph/schema_definition/scripting/script.rb +1 -1
- data/lib/elastic_graph/schema_definition/scripting/scripts/update/index_data.painless +0 -1
- data/lib/elastic_graph/schema_definition/state.rb +4 -1
- data/lib/elastic_graph/schema_definition/test_support.rb +23 -3
- metadata +32 -30
@@ -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
|
@@ -45,7 +45,8 @@ module ElasticGraph
|
|
45
45
|
[type] + schema_def_state.factory.build_relay_pagination_types(type.name, support_pagination: false) do |t|
|
46
46
|
# Record metadata that is necessary for elasticgraph-graphql to correctly recognize and handle
|
47
47
|
# this sub-aggregation correctly.
|
48
|
-
t.
|
48
|
+
t.override_runtime_metadata(elasticgraph_category: :nested_sub_aggregation_connection)
|
49
|
+
t.default_graphql_resolver = :object_without_lookahead
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
@@ -116,6 +117,7 @@ module ElasticGraph
|
|
116
117
|
schema_def_state.sub_aggregation_paths_for(nested_field_ref.parent_type).map do |path|
|
117
118
|
schema_def_state.factory.new_object_type type_ref.as_sub_aggregation(parent_doc_types: path.parent_doc_types).name do |t|
|
118
119
|
t.documentation "Return type representing a bucket of `#{name}` objects for a sub-aggregation within each `#{type_ref.as_parent_aggregation(parent_doc_types: path.parent_doc_types).name}`."
|
120
|
+
t.default_graphql_resolver = :object_without_lookahead
|
119
121
|
|
120
122
|
t.field schema_def_state.schema_elements.count_detail, "AggregationCountDetail", graphql_only: true do |f|
|
121
123
|
f.documentation "Details of the count of `#{name}` documents in a sub-aggregation bucket."
|
@@ -163,6 +165,7 @@ module ElasticGraph
|
|
163
165
|
schema_def_state.factory.new_object_type agg_sub_aggs_type_ref.name do |t|
|
164
166
|
under_field_description = "under `#{path.field_path_string}` " unless path.field_path.empty?
|
165
167
|
t.documentation "Provides access to the `#{schema_def_state.schema_elements.sub_aggregations}` #{under_field_description}within each `#{type_ref.as_parent_aggregation(parent_doc_types: path.parent_doc_types).name}`."
|
168
|
+
t.default_graphql_resolver = :object_with_lookahead
|
166
169
|
|
167
170
|
sub_aggregatable_fields.each do |field|
|
168
171
|
if field.nested?
|
@@ -225,7 +228,8 @@ module ElasticGraph
|
|
225
228
|
|
226
229
|
# Record metadata that is necessary for elasticgraph-graphql to correctly recognize and handle
|
227
230
|
# this indexed aggregation type correctly.
|
228
|
-
t.
|
231
|
+
t.default_graphql_resolver = :object_without_lookahead
|
232
|
+
t.override_runtime_metadata(source_type: name, elasticgraph_category: :indexed_aggregation)
|
229
233
|
end
|
230
234
|
end
|
231
235
|
|
@@ -236,6 +240,7 @@ module ElasticGraph
|
|
236
240
|
|
237
241
|
new_non_empty_object_type type_ref.as_grouped_by.name do |t|
|
238
242
|
t.documentation "Type used to specify the `#{name}` fields to group by for aggregations."
|
243
|
+
t.default_graphql_resolver = :object_with_lookahead
|
239
244
|
|
240
245
|
graphql_fields_by_name.values.each do |field|
|
241
246
|
field.define_grouped_by_field(t)
|
@@ -250,6 +255,7 @@ module ElasticGraph
|
|
250
255
|
|
251
256
|
new_non_empty_object_type type_ref.as_aggregated_values.name do |t|
|
252
257
|
t.documentation "Type used to perform aggregation computations on `#{name}` fields."
|
258
|
+
t.default_graphql_resolver = :object_with_lookahead
|
253
259
|
|
254
260
|
graphql_fields_by_name.values.each do |field|
|
255
261
|
field.define_aggregated_values_field(t)
|
@@ -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
|
@@ -110,6 +110,64 @@ module ElasticGraph
|
|
110
110
|
# Record that we are now generating results so that caching can kick in.
|
111
111
|
state.user_definition_complete = true
|
112
112
|
state.user_definition_complete_callbacks.each(&:call)
|
113
|
+
define_root_graphql_type
|
114
|
+
end
|
115
|
+
|
116
|
+
def define_root_graphql_type
|
117
|
+
state.api.object_type "Query" do |query_type|
|
118
|
+
query_type.documentation "The query entry point for the entire schema."
|
119
|
+
query_type.default_graphql_resolver = nil
|
120
|
+
|
121
|
+
state.types_by_name.values.select(&:indexed?).sort_by(&:name).each do |type|
|
122
|
+
# @type var indexed_type: Mixins::HasIndices & _Type
|
123
|
+
indexed_type = _ = type
|
124
|
+
|
125
|
+
query_type.relates_to_many(
|
126
|
+
indexed_type.plural_root_query_field_name,
|
127
|
+
indexed_type.name,
|
128
|
+
via: "ignore",
|
129
|
+
dir: :in,
|
130
|
+
singular: indexed_type.singular_root_query_field_name
|
131
|
+
) do |f|
|
132
|
+
f.documentation "Fetches `#{indexed_type.name}`s based on the provided arguments."
|
133
|
+
f.resolver = :list_records
|
134
|
+
f.hide_relationship_runtime_metadata = true
|
135
|
+
indexed_type.root_query_fields_customizations&.call(f)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Add additional efficiency hints to the aggregation field documentation if we have any such hints.
|
139
|
+
# This needs to be outside the `relates_to_many` block because `relates_to_many` adds its own "suffix" to
|
140
|
+
# the field documentation, and here we add another one.
|
141
|
+
if (agg_efficiency_hint = aggregation_efficiency_hints_for(indexed_type.derived_indexed_types))
|
142
|
+
agg_name = state.schema_elements.normalize_case("#{indexed_type.singular_root_query_field_name}_aggregations")
|
143
|
+
agg_field = query_type.graphql_fields_by_name.fetch(agg_name)
|
144
|
+
agg_field.documentation "#{agg_field.doc_comment}\n\n#{agg_efficiency_hint}"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
state.built_in_types_customization_blocks.each do |customization_block|
|
149
|
+
customization_block.call(query_type)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def aggregation_efficiency_hints_for(derived_indexed_types)
|
155
|
+
return nil if derived_indexed_types.empty?
|
156
|
+
|
157
|
+
hints = derived_indexed_types.map do |type|
|
158
|
+
derived_indexing_type = state.types_by_name.fetch(type.destination_type_ref.name)
|
159
|
+
alternate_field_name = (_ = derived_indexing_type).plural_root_query_field_name
|
160
|
+
grouping_field = type.id_source
|
161
|
+
|
162
|
+
" - The root `#{alternate_field_name}` field groups by `#{grouping_field}`"
|
163
|
+
end
|
164
|
+
|
165
|
+
<<~EOS
|
166
|
+
Note: aggregation queries are relatively expensive, and some fields have been pre-aggregated to allow
|
167
|
+
more efficient queries for some common aggregation cases:
|
168
|
+
|
169
|
+
#{hints.join("\n")}
|
170
|
+
EOS
|
113
171
|
end
|
114
172
|
|
115
173
|
def json_schema_with_metadata_merger
|
@@ -144,7 +202,7 @@ module ElasticGraph
|
|
144
202
|
def build_runtime_metadata
|
145
203
|
extra_update_targets_by_object_type_name = identify_extra_update_targets_by_object_type_name
|
146
204
|
|
147
|
-
object_types_by_name =
|
205
|
+
object_types_by_name = all_types
|
148
206
|
.select { |t| t.respond_to?(:graphql_fields_by_name) }
|
149
207
|
.to_h { |type| [type.name, (_ = type).runtime_metadata(extra_update_targets_by_object_type_name.fetch(type.name) { [] })] }
|
150
208
|
|
@@ -157,7 +215,7 @@ module ElasticGraph
|
|
157
215
|
.filter_map { |type| enum_generator.sort_order_enum_for(_ = type) }
|
158
216
|
.to_h { |enum_type| [(_ = enum_type).name, (_ = enum_type).runtime_metadata] }
|
159
217
|
|
160
|
-
enum_types_by_name =
|
218
|
+
enum_types_by_name = all_types
|
161
219
|
.grep(SchemaElements::EnumType) # : ::Array[SchemaElements::EnumType]
|
162
220
|
.to_h { |t| [t.name, t.runtime_metadata] }
|
163
221
|
.merge(indexed_enum_types_by_name)
|
@@ -173,8 +231,9 @@ module ElasticGraph
|
|
173
231
|
index_definitions_by_name: index_definitions_by_name,
|
174
232
|
schema_element_names: state.schema_elements,
|
175
233
|
graphql_extension_modules: state.graphql_extension_modules,
|
234
|
+
graphql_resolvers_by_name: state.graphql_resolvers_by_name,
|
176
235
|
static_script_ids_by_scoped_name: STATIC_SCRIPT_REPO.script_ids_by_scoped_name
|
177
|
-
)
|
236
|
+
).tap { |rm| verify_runtime_metadata(rm) }
|
178
237
|
end
|
179
238
|
|
180
239
|
# Builds a map, keyed by object type name, of extra `update_targets` that have been generated
|
@@ -183,7 +242,9 @@ module ElasticGraph
|
|
183
242
|
sourced_field_errors = [] # : ::Array[::String]
|
184
243
|
relationship_errors = [] # : ::Array[::String]
|
185
244
|
|
186
|
-
state.object_types_by_name.values.each_with_object(
|
245
|
+
state.object_types_by_name.except("Query").values.each_with_object(
|
246
|
+
::Hash.new { |h, k| h[k] = [] } # : ::Hash[untyped, ::Array[SchemaArtifacts::RuntimeMetadata::UpdateTarget]]
|
247
|
+
) do |object_type, accum|
|
187
248
|
fields_with_sources_by_relationship_name =
|
188
249
|
if object_type.indices.empty?
|
189
250
|
# only indexed types can have `sourced_from` fields, and resolving `fields_with_sources` on an unindexed union type
|
@@ -251,7 +312,7 @@ module ElasticGraph
|
|
251
312
|
state.object_types_by_name.values.each(&:verify_graphql_correctness!)
|
252
313
|
|
253
314
|
type_defs = state.factory
|
254
|
-
.new_graphql_sdl_enumerator(
|
315
|
+
.new_graphql_sdl_enumerator(all_types)
|
255
316
|
.map { |sdl| strip_trailing_whitespace(sdl) }
|
256
317
|
|
257
318
|
[type_defs + state.sdl_parts].join("\n\n")
|
@@ -283,7 +344,9 @@ module ElasticGraph
|
|
283
344
|
|
284
345
|
def json_schema_indexing_field_types_by_name
|
285
346
|
@json_schema_indexing_field_types_by_name ||= state
|
286
|
-
.types_by_name
|
347
|
+
.types_by_name
|
348
|
+
.except("Query")
|
349
|
+
.values
|
287
350
|
.reject do |t|
|
288
351
|
derived_indexing_type_names.include?(t.name) ||
|
289
352
|
# Skip graphql framework types
|
@@ -293,6 +356,54 @@ module ElasticGraph
|
|
293
356
|
.to_h { |type| [type.name, type.to_indexing_field_type] }
|
294
357
|
end
|
295
358
|
|
359
|
+
def verify_runtime_metadata(runtime_metadata)
|
360
|
+
registered_resolvers = runtime_metadata.graphql_resolvers_by_name
|
361
|
+
|
362
|
+
fields_by_resolvers = ::Hash.new { |h, k| h[k] = [] } # : ::Hash[::Symbol, ::Array[::String]]
|
363
|
+
runtime_metadata
|
364
|
+
.object_types_by_name
|
365
|
+
.each do |type_name, type|
|
366
|
+
type.graphql_fields_by_name.each do |field_name, field|
|
367
|
+
if (resolver = field.resolver)
|
368
|
+
fields_by_resolvers[resolver] << "#{type_name}.#{field_name}"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
unused_resolvers = registered_resolvers.except(*fields_by_resolvers.keys).reject do |name, res|
|
374
|
+
# Ignore our built-in resolvers.
|
375
|
+
res.resolver_ref.fetch("require_path").start_with?("elastic_graph/graphql/resolvers/")
|
376
|
+
end.keys
|
377
|
+
|
378
|
+
unless unused_resolvers.empty?
|
379
|
+
state.output.puts <<~EOS
|
380
|
+
WARNING: #{unused_resolvers.size} GraphQL resolver(s) have been registered but are unused:
|
381
|
+
- #{unused_resolvers.sort.join("\n - ")}
|
382
|
+
These resolvers can be removed.
|
383
|
+
EOS
|
384
|
+
end
|
385
|
+
|
386
|
+
undefined_resolvers = fields_by_resolvers.except(*registered_resolvers.keys)
|
387
|
+
unless undefined_resolvers.empty?
|
388
|
+
resolver_errors = undefined_resolvers.sort_by(&:first).map do |resolver, fields|
|
389
|
+
<<~EOS.strip
|
390
|
+
GraphQL resolver `#{resolver.inspect}` is unregistered but is assigned to #{fields.size} field(s):
|
391
|
+
|
392
|
+
- #{fields.sort.join("\n - ")}
|
393
|
+
EOS
|
394
|
+
end
|
395
|
+
|
396
|
+
raise Errors::SchemaError, <<~EOS
|
397
|
+
#{resolver_errors.join("\n\n")}
|
398
|
+
|
399
|
+
To continue, register the named resolvers with `schema.register_graphql_resolver`
|
400
|
+
or update the fields listed above to use one of the other registered resolvers:
|
401
|
+
|
402
|
+
- #{registered_resolvers.keys.map(&:inspect).sort.join("\n - ")}
|
403
|
+
EOS
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
296
407
|
def strip_trailing_whitespace(string)
|
297
408
|
string.gsub(/ +$/, "")
|
298
409
|
end
|
@@ -300,14 +411,17 @@ module ElasticGraph
|
|
300
411
|
def check_for_circular_dependencies!
|
301
412
|
return if @no_circular_dependencies
|
302
413
|
|
303
|
-
referenced_types_by_source_type =
|
414
|
+
referenced_types_by_source_type = ::Hash.new { |h, k| h[k] = ::Set.new } # : ::Hash[::String, ::Set[::String]]
|
415
|
+
state.types_by_name
|
304
416
|
.reject { |_, type| type.graphql_only? }
|
305
|
-
.
|
306
|
-
recursively_add_referenced_types_to(state.type_ref(type_name),
|
417
|
+
.each do |type_name, _|
|
418
|
+
recursively_add_referenced_types_to(state.type_ref(type_name), referenced_types_by_source_type)
|
307
419
|
end
|
308
420
|
|
309
421
|
circular_reference_sets = referenced_types_by_source_type
|
422
|
+
# standard:disable Style/HashSlice -- https://github.com/rubocop/rubocop/issues/13885
|
310
423
|
.select { |source_type, referenced_types| referenced_types.include?(source_type) }
|
424
|
+
# standard:enable Style/HashSlice
|
311
425
|
.values
|
312
426
|
.uniq
|
313
427
|
|
@@ -341,9 +455,15 @@ module ElasticGraph
|
|
341
455
|
end
|
342
456
|
end
|
343
457
|
|
344
|
-
def
|
345
|
-
@
|
346
|
-
related_types =
|
458
|
+
def all_types
|
459
|
+
@all_types ||= state.types_by_name.values.flat_map do |registered_type|
|
460
|
+
related_types =
|
461
|
+
if registered_type.name == "Query"
|
462
|
+
[registered_type]
|
463
|
+
else
|
464
|
+
[registered_type] + registered_type.derived_graphql_types
|
465
|
+
end
|
466
|
+
|
347
467
|
apply_customizations_to(related_types, registered_type)
|
348
468
|
related_types
|
349
469
|
end
|
@@ -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
|
@@ -178,9 +178,9 @@ module ElasticGraph
|
|
178
178
|
end
|
179
179
|
|
180
180
|
def report_json_schema_merge_errors(merged_results)
|
181
|
-
json_schema_versions_by_missing_field = ::Hash.new { |h, k| h[k] = [] }
|
182
|
-
json_schema_versions_by_missing_type = ::Hash.new { |h, k| h[k] = [] }
|
183
|
-
json_schema_versions_by_missing_necessary_field = ::Hash.new { |h, k| h[k] = [] }
|
181
|
+
json_schema_versions_by_missing_field = ::Hash.new { |h, k| h[k] = [] } # : ::Hash[::String, ::Array[::Integer]]
|
182
|
+
json_schema_versions_by_missing_type = ::Hash.new { |h, k| h[k] = [] } # : ::Hash[::String, ::Array[::Integer]]
|
183
|
+
json_schema_versions_by_missing_necessary_field = ::Hash.new { |h, k| h[k] = [] } # : ::Hash[Indexing::JSONSchemaWithMetadata::MissingNecessaryField, ::Array[::Integer]]
|
184
184
|
|
185
185
|
merged_results.each do |result|
|
186
186
|
result.missing_fields.each do |field|
|
@@ -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
|
@@ -181,6 +181,7 @@ module ElasticGraph
|
|
181
181
|
register_enum_types
|
182
182
|
register_date_and_time_grouped_by_types
|
183
183
|
register_standard_elastic_graph_types
|
184
|
+
register_standard_graphql_resolvers
|
184
185
|
end
|
185
186
|
|
186
187
|
private
|
@@ -281,11 +282,11 @@ module ElasticGraph
|
|
281
282
|
f.default false
|
282
283
|
end
|
283
284
|
|
284
|
-
# any_of/not don't really make sense on this filter because it doesn't make sense
|
285
|
-
# apply an OR operator or negation to the fields of this type since they are all an
|
285
|
+
# any_of/all_of/not don't really make sense on this filter because it doesn't make sense
|
286
|
+
# to apply an OR operator or negation to the fields of this type since they are all an
|
286
287
|
# indivisible part of a single filter operation on a specific field. So we remove them
|
287
288
|
# here.
|
288
|
-
|
289
|
+
remove_any_of_and_all_of_and_not_filter_operators_on(t)
|
289
290
|
end
|
290
291
|
|
291
292
|
register_filter "MatchesPhrase" do |t|
|
@@ -299,11 +300,11 @@ module ElasticGraph
|
|
299
300
|
f.documentation "The input phrase to search for."
|
300
301
|
end
|
301
302
|
|
302
|
-
# any_of/not don't really make sense on this filter because it doesn't make
|
303
|
-
# apply an OR operator or negation to the fields of this type since they are all an
|
303
|
+
# any_of/all_of/not don't really make sense on this filter because it doesn't make
|
304
|
+
# to apply an OR operator or negation to the fields of this type since they are all an
|
304
305
|
# indivisible part of a single filter operation on a specific field. So we remove them
|
305
306
|
# here.
|
306
|
-
|
307
|
+
remove_any_of_and_all_of_and_not_filter_operators_on(t)
|
307
308
|
end
|
308
309
|
|
309
310
|
# This is defined as a built-in ElasticGraph type so that we can leverage Elasticsearch/OpenSearch GeoLocation features
|
@@ -371,11 +372,11 @@ module ElasticGraph
|
|
371
372
|
f.documentation "Determines the unit of the specified `#{names.max_distance}`."
|
372
373
|
end
|
373
374
|
|
374
|
-
# any_of/not don't really make sense on this filter because it doesn't make sense
|
375
|
-
# apply an OR operator or negation to the fields of this type since they are all an
|
375
|
+
# any_of/all_of/not don't really make sense on this filter because it doesn't make sense
|
376
|
+
# to apply an OR operator or negation to the fields of this type since they are all an
|
376
377
|
# indivisible part of a single filter operation on a specific field. So we remove them
|
377
378
|
# here.
|
378
|
-
|
379
|
+
remove_any_of_and_all_of_and_not_filter_operators_on(t)
|
379
380
|
end
|
380
381
|
|
381
382
|
# Note: `has_next_page`/`has_previous_page` are required to be non-null by the relay
|
@@ -393,6 +394,8 @@ module ElasticGraph
|
|
393
394
|
# to go from non-null to null, but is not a breaking change to make it non-null
|
394
395
|
# in the future.
|
395
396
|
register_framework_object_type "PageInfo" do |t|
|
397
|
+
t.default_graphql_resolver = :object_without_lookahead
|
398
|
+
|
396
399
|
t.documentation <<~EOS
|
397
400
|
Provides information about the specific fetched page. This implements the `PageInfo`
|
398
401
|
specification from the [Relay GraphQL Cursor Connections
|
@@ -509,6 +512,7 @@ module ElasticGraph
|
|
509
512
|
|
510
513
|
register_framework_object_type "AggregationCountDetail" do |t|
|
511
514
|
t.documentation "Provides detail about an aggregation `#{names.count}`."
|
515
|
+
t.default_graphql_resolver = :object_without_lookahead
|
512
516
|
|
513
517
|
t.field names.approximate_value, "JsonSafeLong!", graphql_only: true do |f|
|
514
518
|
f.documentation <<~EOS
|
@@ -728,11 +732,11 @@ module ElasticGraph
|
|
728
732
|
f.default "UTC"
|
729
733
|
end
|
730
734
|
|
731
|
-
# With our initial implementation of `time_of_day` filtering, it's tricky to support `any_of`/`not` within
|
735
|
+
# With our initial implementation of `time_of_day` filtering, it's tricky to support `any_of`/`all_of`/`not` within
|
732
736
|
# the `time_of_day: {...}` input object. They are still supported outside of `time_of_day` (on the parent
|
733
737
|
# input object) so no functionality is losts by omitting these. Also, this aligns with our `GeoLocationDistanceFilterInput`
|
734
738
|
# which is a similarly complex filter where we didn't include them.
|
735
|
-
|
739
|
+
remove_any_of_and_all_of_and_not_filter_operators_on(t)
|
736
740
|
end
|
737
741
|
end
|
738
742
|
|
@@ -1290,7 +1294,8 @@ module ElasticGraph
|
|
1290
1294
|
date = schema_def_state.type_ref("Date")
|
1291
1295
|
register_framework_object_type date.as_grouped_by.name do |t|
|
1292
1296
|
t.documentation "Allows for grouping `Date` values based on the desired return type."
|
1293
|
-
t.
|
1297
|
+
t.default_graphql_resolver = :object_with_lookahead
|
1298
|
+
t.override_runtime_metadata(elasticgraph_category: :date_grouped_by_object)
|
1294
1299
|
|
1295
1300
|
t.field names.as_date, "Date", graphql_only: true do |f|
|
1296
1301
|
f.documentation "Used when grouping on the full `Date` value."
|
@@ -1307,7 +1312,8 @@ module ElasticGraph
|
|
1307
1312
|
date_time = schema_def_state.type_ref("DateTime")
|
1308
1313
|
register_framework_object_type date_time.as_grouped_by.name do |t|
|
1309
1314
|
t.documentation "Allows for grouping `DateTime` values based on the desired return type."
|
1310
|
-
t.
|
1315
|
+
t.default_graphql_resolver = :object_with_lookahead
|
1316
|
+
t.override_runtime_metadata(elasticgraph_category: :date_grouped_by_object)
|
1311
1317
|
|
1312
1318
|
t.field names.as_date_time, "DateTime", graphql_only: true do |f|
|
1313
1319
|
f.documentation "Used when grouping on the full `DateTime` value."
|
@@ -1363,6 +1369,31 @@ module ElasticGraph
|
|
1363
1369
|
end
|
1364
1370
|
end
|
1365
1371
|
|
1372
|
+
def register_standard_graphql_resolvers
|
1373
|
+
require(require_path = "elastic_graph/graphql/resolvers/get_record_field_value")
|
1374
|
+
schema_def_api.register_graphql_resolver :get_record_field_value,
|
1375
|
+
GraphQL::Resolvers::GetRecordFieldValue,
|
1376
|
+
defined_at: require_path
|
1377
|
+
|
1378
|
+
require(require_path = "elastic_graph/graphql/resolvers/list_records")
|
1379
|
+
schema_def_api.register_graphql_resolver :list_records,
|
1380
|
+
GraphQL::Resolvers::ListRecords,
|
1381
|
+
defined_at: require_path
|
1382
|
+
|
1383
|
+
require(require_path = "elastic_graph/graphql/resolvers/nested_relationships")
|
1384
|
+
schema_def_api.register_graphql_resolver :nested_relationships,
|
1385
|
+
GraphQL::Resolvers::NestedRelationships,
|
1386
|
+
defined_at: require_path
|
1387
|
+
|
1388
|
+
require(require_path = "elastic_graph/graphql/resolvers/object")
|
1389
|
+
schema_def_api.register_graphql_resolver :object_with_lookahead,
|
1390
|
+
GraphQL::Resolvers::Object::WithLookahead,
|
1391
|
+
defined_at: require_path
|
1392
|
+
schema_def_api.register_graphql_resolver :object_without_lookahead,
|
1393
|
+
GraphQL::Resolvers::Object::WithoutLookahead,
|
1394
|
+
defined_at: require_path
|
1395
|
+
end
|
1396
|
+
|
1366
1397
|
def define_date_grouping_arguments(grouping_field, omit_timezone: false)
|
1367
1398
|
define_calendar_type_grouping_arguments(grouping_field, schema_def_state.type_ref("Date"), <<~EOS, omit_timezone: omit_timezone)
|
1368
1399
|
For example, when grouping by `WEEK`, you can shift by 1 day to change what day-of-week weeks are considered to start on.
|
@@ -1515,8 +1546,9 @@ module ElasticGraph
|
|
1515
1546
|
schema_def_state.register_input_type(input_type)
|
1516
1547
|
end
|
1517
1548
|
|
1518
|
-
def
|
1549
|
+
def remove_any_of_and_all_of_and_not_filter_operators_on(type)
|
1519
1550
|
type.graphql_fields_by_name.delete(names.any_of)
|
1551
|
+
type.graphql_fields_by_name.delete(names.all_of)
|
1520
1552
|
type.graphql_fields_by_name.delete(names.not)
|
1521
1553
|
end
|
1522
1554
|
end
|
@@ -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
|
@@ -92,7 +92,7 @@ module ElasticGraph
|
|
92
92
|
:aggregated_values_customizations, :sort_order_enum_value_customizations,
|
93
93
|
:args, :sortable, :filterable, :aggregatable, :groupable, :graphql_only, :source, :runtime_field_script, :relationship, :singular_name,
|
94
94
|
:computation_detail, :non_nullable_in_json_schema, :backing_indexing_field, :as_input,
|
95
|
-
:legacy_grouping_schema, :name_in_index
|
95
|
+
:legacy_grouping_schema, :name_in_index, :resolver
|
96
96
|
)
|
97
97
|
include Mixins::HasDocumentation
|
98
98
|
include Mixins::HasDirectives
|
@@ -103,10 +103,9 @@ module ElasticGraph
|
|
103
103
|
def initialize(
|
104
104
|
name:, type:, parent_type:, schema_def_state:,
|
105
105
|
accuracy_confidence: :high, name_in_index: name,
|
106
|
-
runtime_metadata_graphql_field: SchemaArtifacts::RuntimeMetadata::GraphQLField::EMPTY,
|
107
106
|
type_for_derived_types: nil, graphql_only: nil, singular: nil,
|
108
107
|
sortable: nil, filterable: nil, aggregatable: nil, groupable: nil,
|
109
|
-
backing_indexing_field: nil, as_input: false, legacy_grouping_schema: false
|
108
|
+
backing_indexing_field: nil, as_input: false, legacy_grouping_schema: false, resolver: nil
|
110
109
|
)
|
111
110
|
type_ref = schema_def_state.type_ref(type)
|
112
111
|
super(
|
@@ -137,10 +136,11 @@ module ElasticGraph
|
|
137
136
|
non_nullable_in_json_schema: false,
|
138
137
|
backing_indexing_field: backing_indexing_field,
|
139
138
|
as_input: as_input,
|
140
|
-
legacy_grouping_schema: legacy_grouping_schema
|
139
|
+
legacy_grouping_schema: legacy_grouping_schema,
|
140
|
+
resolver: resolver
|
141
141
|
)
|
142
142
|
|
143
|
-
if name != name_in_index && name_in_index
|
143
|
+
if name != name_in_index && name_in_index.include?(".") && !graphql_only
|
144
144
|
raise Errors::SchemaError, "#{self} has an invalid `name_in_index`: #{name_in_index.inspect}. Only `graphql_only: true` fields can have a `name_in_index` that references a child field."
|
145
145
|
end
|
146
146
|
|
@@ -735,9 +735,13 @@ module ElasticGraph
|
|
735
735
|
.as_static_derived_type(filter_field_category(for_single_value))
|
736
736
|
.name
|
737
737
|
|
738
|
-
params = to_h
|
739
|
-
|
740
|
-
|
738
|
+
params = to_h.slice(*@@initialize_param_names).merge(
|
739
|
+
type: filter_type,
|
740
|
+
parent_type: parent_type,
|
741
|
+
name_in_index: name_in_index,
|
742
|
+
type_for_derived_types: nil,
|
743
|
+
resolver: nil
|
744
|
+
)
|
741
745
|
|
742
746
|
schema_def_state.factory.new_field(**params).tap do |f|
|
743
747
|
f.documentation derived_documentation(
|
@@ -925,7 +929,8 @@ module ElasticGraph
|
|
925
929
|
SchemaArtifacts::RuntimeMetadata::GraphQLField.new(
|
926
930
|
name_in_index: name_in_index,
|
927
931
|
computation_detail: computation_detail,
|
928
|
-
relation: relationship&.runtime_metadata
|
932
|
+
relation: relationship&.runtime_metadata,
|
933
|
+
resolver: resolver
|
929
934
|
)
|
930
935
|
end
|
931
936
|
|