elasticgraph-schema_definition 1.1.0 → 1.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/README.md +0 -4
- data/lib/elastic_graph/schema_definition/api.rb +20 -1
- data/lib/elastic_graph/schema_definition/factory.rb +5 -5
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/event_envelope.rb +5 -2
- data/lib/elastic_graph/schema_definition/indexing/index.rb +21 -3
- data/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb +8 -8
- data/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb +2 -2
- data/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb +1 -1
- data/lib/elastic_graph/schema_definition/jruby_patches.rb +59 -0
- data/lib/elastic_graph/schema_definition/mixins/has_indices.rb +122 -18
- data/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb +21 -12
- data/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb +32 -1
- data/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb +1 -14
- data/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb +16 -5
- data/lib/elastic_graph/schema_definition/rake_tasks.rb +13 -11
- data/lib/elastic_graph/schema_definition/results.rb +26 -28
- data/lib/elastic_graph/schema_definition/schema_artifact_manager.rb +3 -2
- data/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb +13 -8
- data/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb +0 -5
- data/lib/elastic_graph/schema_definition/schema_elements/{enums_for_indexed_types.rb → enums_for_directly_queryable_types.rb} +10 -10
- data/lib/elastic_graph/schema_definition/schema_elements/field.rb +22 -5
- data/lib/elastic_graph/schema_definition/schema_elements/object_type.rb +11 -1
- data/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb +0 -5
- data/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.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 +12 -0
- data/lib/elastic_graph/schema_definition/state.rb +17 -5
- metadata +29 -48
|
@@ -33,7 +33,7 @@ module ElasticGraph
|
|
|
33
33
|
def derived_graphql_types
|
|
34
34
|
return [] if graphql_only?
|
|
35
35
|
|
|
36
|
-
indexed_agg_type =
|
|
36
|
+
indexed_agg_type = to_root_aggregation_type
|
|
37
37
|
indexed_aggregation_pagination_types =
|
|
38
38
|
if indexed_agg_type
|
|
39
39
|
schema_def_state.factory.build_relay_pagination_types(indexed_agg_type.name)
|
|
@@ -51,7 +51,7 @@ module ElasticGraph
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
document_pagination_types =
|
|
54
|
-
if
|
|
54
|
+
if directly_queryable?
|
|
55
55
|
schema_def_state.factory.build_relay_pagination_types(name, include_total_edge_count: true, derived_indexed_types: (_ = self).derived_indexed_types)
|
|
56
56
|
elsif schema_def_state.paginated_collection_element_types.include?(name)
|
|
57
57
|
schema_def_state.factory.build_relay_pagination_types(name, include_total_edge_count: true)
|
|
@@ -59,7 +59,7 @@ module ElasticGraph
|
|
|
59
59
|
[] # : ::Array[SchemaElements::ObjectType]
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
sort_order_enum_type = schema_def_state.
|
|
62
|
+
sort_order_enum_type = schema_def_state.enums_for_directly_queryable_types.sort_order_enum_for(self)
|
|
63
63
|
derived_sort_order_enum_types = [sort_order_enum_type].compact + (sort_order_enum_type&.derived_graphql_types || [])
|
|
64
64
|
|
|
65
65
|
to_input_filters +
|
|
@@ -87,6 +87,17 @@ module ElasticGraph
|
|
|
87
87
|
return [] if does_not_support?(&:filterable?)
|
|
88
88
|
|
|
89
89
|
schema_def_state.factory.build_standard_filter_input_types_for_index_object_type(name) do |t|
|
|
90
|
+
if abstract?
|
|
91
|
+
t.field schema_def_state.schema_elements._typename, schema_def_state.type_ref("String").as_filter_input.name, name_in_index: "__typename" do |f|
|
|
92
|
+
f.documentation <<~EOS
|
|
93
|
+
Filters `#{name}` records by concrete type. Only concrete type names are valid values —
|
|
94
|
+
filtering on an abstract type name will match nothing, since records only have concrete
|
|
95
|
+
type names for their `__typename` value.
|
|
96
|
+
Analogous to the `__typename` return field.
|
|
97
|
+
EOS
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
90
101
|
graphql_fields_by_name.values.each do |field|
|
|
91
102
|
if field.filterable?
|
|
92
103
|
t.graphql_fields_by_name[field.name] = field.to_filter_field(parent_type: t)
|
|
@@ -198,8 +209,8 @@ module ElasticGraph
|
|
|
198
209
|
end
|
|
199
210
|
end
|
|
200
211
|
|
|
201
|
-
def
|
|
202
|
-
return nil unless
|
|
212
|
+
def to_root_aggregation_type
|
|
213
|
+
return nil unless directly_queryable?
|
|
203
214
|
|
|
204
215
|
schema_def_state.factory.new_object_type type_ref.as_aggregation.name do |t|
|
|
205
216
|
t.documentation "Return type representing a bucket of `#{name}` documents for an aggregations query."
|
|
@@ -171,18 +171,20 @@ module ElasticGraph
|
|
|
171
171
|
end
|
|
172
172
|
|
|
173
173
|
def schema_def_api
|
|
174
|
-
|
|
174
|
+
@schema_def_api ||= begin
|
|
175
|
+
require "elastic_graph/schema_definition/api"
|
|
175
176
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
177
|
+
API.new(
|
|
178
|
+
@schema_element_names,
|
|
179
|
+
@index_document_sizes,
|
|
180
|
+
extension_modules: @extension_modules,
|
|
181
|
+
derived_type_name_formats: @derived_type_name_formats,
|
|
182
|
+
type_name_overrides: @type_name_overrides,
|
|
183
|
+
enum_value_overrides_by_type: @enum_value_overrides_by_type,
|
|
184
|
+
output: @output
|
|
185
|
+
).tap do |api|
|
|
186
|
+
api.as_active_instance { load @path_to_schema.to_s }
|
|
187
|
+
end
|
|
186
188
|
end
|
|
187
189
|
end
|
|
188
190
|
end
|
|
@@ -119,28 +119,28 @@ module ElasticGraph
|
|
|
119
119
|
query_type.documentation "The query entry point for the entire schema."
|
|
120
120
|
query_type.resolve_fields_with nil
|
|
121
121
|
|
|
122
|
-
state.
|
|
123
|
-
# @type var
|
|
124
|
-
|
|
122
|
+
state.object_types_by_name.values.select(&:directly_queryable?).sort_by(&:name).each do |type|
|
|
123
|
+
# @type var root_doc_type: Mixins::HasIndices & _Type
|
|
124
|
+
root_doc_type = _ = type
|
|
125
125
|
|
|
126
126
|
query_type.relates_to_many(
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
root_doc_type.plural_root_query_field_name,
|
|
128
|
+
root_doc_type.name,
|
|
129
129
|
via: "ignore",
|
|
130
130
|
dir: :in,
|
|
131
|
-
singular:
|
|
131
|
+
singular: root_doc_type.singular_root_query_field_name
|
|
132
132
|
) do |f|
|
|
133
|
-
f.documentation "Fetches `#{
|
|
134
|
-
f.resolve_with :
|
|
133
|
+
f.documentation "Fetches `#{root_doc_type.name}`s based on the provided arguments."
|
|
134
|
+
f.resolve_with :indexed_type_root_fields
|
|
135
135
|
f.hide_relationship_runtime_metadata = true
|
|
136
|
-
|
|
136
|
+
root_doc_type.root_query_fields_customizations&.call(f)
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
# Add additional efficiency hints to the aggregation field documentation if we have any such hints.
|
|
140
140
|
# This needs to be outside the `relates_to_many` block because `relates_to_many` adds its own "suffix" to
|
|
141
141
|
# the field documentation, and here we add another one.
|
|
142
|
-
if (agg_efficiency_hint = aggregation_efficiency_hints_for(
|
|
143
|
-
agg_name = state.schema_elements.normalize_case("#{
|
|
142
|
+
if (agg_efficiency_hint = aggregation_efficiency_hints_for(root_doc_type.derived_indexed_types))
|
|
143
|
+
agg_name = state.schema_elements.normalize_case("#{root_doc_type.singular_root_query_field_name}_aggregations")
|
|
144
144
|
agg_field = query_type.graphql_fields_by_name.fetch(agg_name)
|
|
145
145
|
agg_field.documentation "#{agg_field.doc_comment}\n\n#{agg_efficiency_hint}"
|
|
146
146
|
end
|
|
@@ -181,7 +181,7 @@ module ElasticGraph
|
|
|
181
181
|
check_for_circular_dependencies!
|
|
182
182
|
|
|
183
183
|
index_templates, indices = state.object_types_by_name.values
|
|
184
|
-
.filter_map(&:
|
|
184
|
+
.filter_map(&:own_index_def)
|
|
185
185
|
.sort_by(&:name)
|
|
186
186
|
.partition(&:rollover_config)
|
|
187
187
|
|
|
@@ -209,19 +209,19 @@ module ElasticGraph
|
|
|
209
209
|
|
|
210
210
|
scalar_types_by_name = state.scalar_types_by_name.transform_values(&:runtime_metadata)
|
|
211
211
|
|
|
212
|
-
enum_generator = state.factory.
|
|
212
|
+
enum_generator = state.factory.new_enums_for_directly_queryable_types
|
|
213
213
|
|
|
214
|
-
|
|
215
|
-
.select(&:
|
|
214
|
+
sort_order_enum_types_by_name = state.object_types_by_name.values
|
|
215
|
+
.select(&:directly_queryable?)
|
|
216
216
|
.filter_map { |type| enum_generator.sort_order_enum_for(_ = type) }
|
|
217
217
|
.to_h { |enum_type| [(_ = enum_type).name, (_ = enum_type).runtime_metadata] }
|
|
218
218
|
|
|
219
219
|
enum_types_by_name = all_types
|
|
220
220
|
.grep(SchemaElements::EnumType) # : ::Array[SchemaElements::EnumType]
|
|
221
221
|
.to_h { |t| [t.name, t.runtime_metadata] }
|
|
222
|
-
.merge(
|
|
222
|
+
.merge(sort_order_enum_types_by_name)
|
|
223
223
|
|
|
224
|
-
index_definitions_by_name = state.object_types_by_name.values.filter_map(&:
|
|
224
|
+
index_definitions_by_name = state.object_types_by_name.values.filter_map(&:own_index_def).to_h do |index|
|
|
225
225
|
[index.name, index.runtime_metadata]
|
|
226
226
|
end
|
|
227
227
|
|
|
@@ -248,7 +248,7 @@ module ElasticGraph
|
|
|
248
248
|
::Hash.new { |h, k| h[k] = [] } # : ::Hash[untyped, ::Array[SchemaArtifacts::RuntimeMetadata::UpdateTarget]]
|
|
249
249
|
) do |object_type, accum|
|
|
250
250
|
fields_with_sources_by_relationship_name =
|
|
251
|
-
if object_type.
|
|
251
|
+
if object_type.own_index_def.nil?
|
|
252
252
|
# only indexed types can have `sourced_from` fields, and resolving `fields_with_sources` on an unindexed union type
|
|
253
253
|
# such as `_Entity` when we are using apollo can lead to exceptions when multiple entity types have the same field name
|
|
254
254
|
# that use different mapping types.
|
|
@@ -276,7 +276,7 @@ module ElasticGraph
|
|
|
276
276
|
resolved_relationship, relationship_error = relationship_resolver.resolve
|
|
277
277
|
relationship_errors << relationship_error if relationship_error
|
|
278
278
|
|
|
279
|
-
if object_type.
|
|
279
|
+
if object_type.own_index_def && resolved_relationship && sourced_fields.any?
|
|
280
280
|
update_target_resolver = Indexing::UpdateTargetResolver.new(
|
|
281
281
|
object_type: object_type,
|
|
282
282
|
resolved_relationship: resolved_relationship,
|
|
@@ -289,7 +289,7 @@ module ElasticGraph
|
|
|
289
289
|
sourced_field_errors.concat(errors)
|
|
290
290
|
|
|
291
291
|
# Validate that has_had_multiple_sources! has been called when sourced_from is used
|
|
292
|
-
if (index_def = object_type.
|
|
292
|
+
if (index_def = object_type.own_index_def) && !index_def.has_had_multiple_sources_flag
|
|
293
293
|
sourced_field_errors << "Type `#{object_type.name}` uses `sourced_from` fields but its index `#{index_def.name}` " \
|
|
294
294
|
"has not been configured with `has_had_multiple_sources!`. To resolve this, add `i.has_had_multiple_sources!` within the " \
|
|
295
295
|
"`t.index \"#{index_def.name}\"` block. This flag is required because indices with multiple sources can contain " \
|
|
@@ -335,8 +335,8 @@ module ElasticGraph
|
|
|
335
335
|
raise Errors::SchemaError, "`json_schema_version` must be specified in the schema. To resolve, add `schema.json_schema_version 1` in a schema definition block."
|
|
336
336
|
end
|
|
337
337
|
|
|
338
|
-
|
|
339
|
-
.select { |type| type.
|
|
338
|
+
root_document_type_names = state.object_types_by_name.values
|
|
339
|
+
.select { |type| type.root_document_type? && !type.abstract? }
|
|
340
340
|
.reject { |type| derived_indexing_type_names.include?(type.name) }
|
|
341
341
|
.map(&:name)
|
|
342
342
|
|
|
@@ -348,7 +348,7 @@ module ElasticGraph
|
|
|
348
348
|
"$schema" => JSON_META_SCHEMA,
|
|
349
349
|
JSON_SCHEMA_VERSION_KEY => json_schema_version,
|
|
350
350
|
"$defs" => {
|
|
351
|
-
"ElasticGraphEventEnvelope" => Indexing::EventEnvelope.json_schema(
|
|
351
|
+
"ElasticGraphEventEnvelope" => Indexing::EventEnvelope.json_schema(root_document_type_names, json_schema_version)
|
|
352
352
|
}.merge(definitions_by_name)
|
|
353
353
|
}
|
|
354
354
|
end
|
|
@@ -381,16 +381,14 @@ module ElasticGraph
|
|
|
381
381
|
end
|
|
382
382
|
end
|
|
383
383
|
|
|
384
|
-
unused_resolvers = registered_resolvers.except(*fields_by_resolvers.keys).
|
|
385
|
-
# Ignore our built-in resolvers.
|
|
386
|
-
res.resolver_ref.fetch("require_path").start_with?("elastic_graph/graphql/resolvers/")
|
|
387
|
-
end.keys
|
|
384
|
+
unused_resolvers = registered_resolvers.except(*fields_by_resolvers.keys, *state.built_in_graphql_resolvers.to_a).keys
|
|
388
385
|
|
|
389
386
|
unless unused_resolvers.empty?
|
|
390
387
|
state.output.puts <<~EOS
|
|
391
388
|
WARNING: #{unused_resolvers.size} GraphQL resolver(s) have been registered but are unused:
|
|
392
389
|
- #{unused_resolvers.sort.join("\n - ")}
|
|
393
|
-
These resolvers can be removed.
|
|
390
|
+
These resolvers can be removed. If you intended for them to be available as built-in/internal
|
|
391
|
+
resolvers, pass `built_in: true` when registering them.
|
|
394
392
|
EOS
|
|
395
393
|
end
|
|
396
394
|
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
require "did_you_mean"
|
|
10
10
|
require "elastic_graph/constants"
|
|
11
11
|
require "elastic_graph/schema_definition/json_schema_pruner"
|
|
12
|
+
require "elastic_graph/support/graphql_gem_loader"
|
|
12
13
|
require "elastic_graph/support/memoizable_data"
|
|
13
14
|
require "fileutils"
|
|
14
|
-
require "graphql"
|
|
15
|
-
require "graphql/c_parser"
|
|
16
15
|
require "tempfile"
|
|
17
16
|
require "yaml"
|
|
18
17
|
|
|
18
|
+
ElasticGraph::Support::GraphQLGemLoader.load
|
|
19
|
+
|
|
19
20
|
module ElasticGraph
|
|
20
21
|
module SchemaDefinition
|
|
21
22
|
# Manages schema artifacts. Note: not tested directly. Instead, the `RakeTasks` tests drive this class.
|
|
@@ -1425,25 +1425,30 @@ module ElasticGraph
|
|
|
1425
1425
|
require(require_path = "elastic_graph/graphql/resolvers/get_record_field_value")
|
|
1426
1426
|
schema_def_api.register_graphql_resolver :get_record_field_value,
|
|
1427
1427
|
GraphQL::Resolvers::GetRecordFieldValue,
|
|
1428
|
-
defined_at: require_path
|
|
1428
|
+
defined_at: require_path,
|
|
1429
|
+
built_in: true
|
|
1429
1430
|
|
|
1430
|
-
require(require_path = "elastic_graph/graphql/resolvers/
|
|
1431
|
-
schema_def_api.register_graphql_resolver :
|
|
1432
|
-
GraphQL::Resolvers::
|
|
1433
|
-
defined_at: require_path
|
|
1431
|
+
require(require_path = "elastic_graph/graphql/resolvers/indexed_type_root_fields_resolver")
|
|
1432
|
+
schema_def_api.register_graphql_resolver :indexed_type_root_fields,
|
|
1433
|
+
GraphQL::Resolvers::IndexedTypeRootFieldsResolver,
|
|
1434
|
+
defined_at: require_path,
|
|
1435
|
+
built_in: true
|
|
1434
1436
|
|
|
1435
1437
|
require(require_path = "elastic_graph/graphql/resolvers/nested_relationships")
|
|
1436
1438
|
schema_def_api.register_graphql_resolver :nested_relationships,
|
|
1437
1439
|
GraphQL::Resolvers::NestedRelationships,
|
|
1438
|
-
defined_at: require_path
|
|
1440
|
+
defined_at: require_path,
|
|
1441
|
+
built_in: true
|
|
1439
1442
|
|
|
1440
1443
|
require(require_path = "elastic_graph/graphql/resolvers/object")
|
|
1441
1444
|
schema_def_api.register_graphql_resolver :object_with_lookahead,
|
|
1442
1445
|
GraphQL::Resolvers::Object::WithLookahead,
|
|
1443
|
-
defined_at: require_path
|
|
1446
|
+
defined_at: require_path,
|
|
1447
|
+
built_in: true
|
|
1444
1448
|
schema_def_api.register_graphql_resolver :object_without_lookahead,
|
|
1445
1449
|
GraphQL::Resolvers::Object::WithoutLookahead,
|
|
1446
|
-
defined_at: require_path
|
|
1450
|
+
defined_at: require_path,
|
|
1451
|
+
built_in: true
|
|
1447
1452
|
end
|
|
1448
1453
|
|
|
1449
1454
|
def define_date_grouping_arguments(grouping_field, omit_timezone: false)
|
|
@@ -161,11 +161,6 @@ module ElasticGraph
|
|
|
161
161
|
Indexing::FieldType::Enum.new(values_by_name.keys)
|
|
162
162
|
end
|
|
163
163
|
|
|
164
|
-
# @return [false] enum types are never directly indexed
|
|
165
|
-
def indexed?
|
|
166
|
-
false
|
|
167
|
-
end
|
|
168
|
-
|
|
169
164
|
# @return [EnumType] converts the enum type to its input form for when different naming is used for input vs output enums.
|
|
170
165
|
def as_input
|
|
171
166
|
input_name = type_ref
|
|
@@ -12,19 +12,19 @@ require "elastic_graph/schema_artifacts/runtime_metadata/sort_field"
|
|
|
12
12
|
module ElasticGraph
|
|
13
13
|
module SchemaDefinition
|
|
14
14
|
module SchemaElements
|
|
15
|
-
# Responsible for generating enum types based on specific
|
|
15
|
+
# Responsible for generating enum types based on specific directly queryable types.
|
|
16
16
|
#
|
|
17
17
|
# @private
|
|
18
|
-
class
|
|
18
|
+
class EnumsForDirectlyQueryableTypes
|
|
19
19
|
def initialize(schema_def_state)
|
|
20
20
|
@schema_def_state = schema_def_state
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
# Generates a `SortOrder` enum type for the given
|
|
24
|
-
def sort_order_enum_for(
|
|
25
|
-
return nil unless
|
|
23
|
+
# Generates a `SortOrder` enum type for the given directly queryable type.
|
|
24
|
+
def sort_order_enum_for(type)
|
|
25
|
+
return nil unless type.directly_queryable?
|
|
26
26
|
|
|
27
|
-
build_enum(
|
|
27
|
+
build_enum(type, :sort_order, :sortable?, "sorted") do |enum_type, field_path|
|
|
28
28
|
value_name_parts = field_path.map(&:name)
|
|
29
29
|
index_field = field_path.map(&:name_in_index).join(".")
|
|
30
30
|
|
|
@@ -45,12 +45,12 @@ module ElasticGraph
|
|
|
45
45
|
|
|
46
46
|
private
|
|
47
47
|
|
|
48
|
-
def build_enum(
|
|
49
|
-
derived_type_ref =
|
|
48
|
+
def build_enum(type, category, field_predicate, past_tense_verb, &block)
|
|
49
|
+
derived_type_ref = type.type_ref.as_static_derived_type(category)
|
|
50
50
|
|
|
51
51
|
enum = @schema_def_state.factory.new_enum_type(derived_type_ref.name) do |enum_type|
|
|
52
|
-
enum_type.documentation "Enumerates the ways `#{
|
|
53
|
-
define_enum_values_for_type(enum_type,
|
|
52
|
+
enum_type.documentation "Enumerates the ways `#{type.name}`s can be #{past_tense_verb}."
|
|
53
|
+
define_enum_values_for_type(enum_type, type, field_predicate, &block)
|
|
54
54
|
end.as_input
|
|
55
55
|
|
|
56
56
|
enum unless enum.values_by_name.empty?
|
|
@@ -73,6 +73,8 @@ module ElasticGraph
|
|
|
73
73
|
# @private
|
|
74
74
|
# @!attribute [rw] highlightable
|
|
75
75
|
# @private
|
|
76
|
+
# @!attribute [rw] returnable
|
|
77
|
+
# @private
|
|
76
78
|
# @!attribute [rw] source
|
|
77
79
|
# @private
|
|
78
80
|
# @!attribute [rw] runtime_field_script
|
|
@@ -91,7 +93,7 @@ module ElasticGraph
|
|
|
91
93
|
:name, :original_type, :parent_type, :original_type_for_derived_types, :schema_def_state, :accuracy_confidence,
|
|
92
94
|
:filter_customizations, :grouped_by_customizations, :highlights_customizations, :sub_aggregations_customizations,
|
|
93
95
|
:aggregated_values_customizations, :sort_order_enum_value_customizations, :args,
|
|
94
|
-
:sortable, :filterable, :aggregatable, :groupable, :highlightable,
|
|
96
|
+
:sortable, :filterable, :aggregatable, :groupable, :highlightable, :returnable,
|
|
95
97
|
:graphql_only, :source, :runtime_field_script, :relationship, :singular_name,
|
|
96
98
|
:computation_detail, :non_nullable_in_json_schema, :as_input,
|
|
97
99
|
:name_in_index, :resolver
|
|
@@ -106,7 +108,7 @@ module ElasticGraph
|
|
|
106
108
|
name:, type:, parent_type:, schema_def_state:,
|
|
107
109
|
accuracy_confidence: :high, name_in_index: name,
|
|
108
110
|
type_for_derived_types: nil, graphql_only: nil, singular: nil,
|
|
109
|
-
sortable: nil, filterable: nil, aggregatable: nil, groupable: nil, highlightable: nil,
|
|
111
|
+
sortable: nil, filterable: nil, aggregatable: nil, groupable: nil, highlightable: nil, returnable: nil,
|
|
110
112
|
as_input: false, resolver: nil
|
|
111
113
|
)
|
|
112
114
|
type_ref = schema_def_state.type_ref(type)
|
|
@@ -129,6 +131,7 @@ module ElasticGraph
|
|
|
129
131
|
aggregatable: aggregatable,
|
|
130
132
|
groupable: groupable,
|
|
131
133
|
highlightable: highlightable,
|
|
134
|
+
returnable: returnable,
|
|
132
135
|
graphql_only: graphql_only,
|
|
133
136
|
source: nil,
|
|
134
137
|
runtime_field_script: nil,
|
|
@@ -677,10 +680,10 @@ module ElasticGraph
|
|
|
677
680
|
# If the groupability of the field was specified explicitly when the field was defined, use the specified value.
|
|
678
681
|
return groupable unless groupable.nil?
|
|
679
682
|
|
|
680
|
-
# We don't want the `id` field of
|
|
683
|
+
# We don't want the `id` field of a root document type to be available to group by, because it's the unique primary key
|
|
681
684
|
# and the groupings would each contain one document. It's simpler and more efficient to just query the raw documents
|
|
682
685
|
# instead.
|
|
683
|
-
return false if parent_type.
|
|
686
|
+
return false if parent_type.root_document_type? && name == "id"
|
|
684
687
|
|
|
685
688
|
return false if relationship || type.fully_unwrapped.as_object_type&.does_not_support?(&:groupable?)
|
|
686
689
|
|
|
@@ -738,11 +741,22 @@ module ElasticGraph
|
|
|
738
741
|
def highlightable?
|
|
739
742
|
return highlightable unless highlightable.nil?
|
|
740
743
|
return false if relationship
|
|
744
|
+
return false unless returnable?
|
|
741
745
|
return true if HIGHLIGHTABLE_MAPPING_TYPES.include?(mapping_type)
|
|
742
746
|
|
|
743
747
|
type_for_derived_types.fully_unwrapped.as_object_type&.supports?(&:highlightable?)
|
|
744
748
|
end
|
|
745
749
|
|
|
750
|
+
# Indicates if this field is returnable in GraphQL query responses. When `false`, the field will
|
|
751
|
+
# still be available for filtering, sorting, grouping, and aggregation, but will not appear in the
|
|
752
|
+
# GraphQL output type and its data will be excluded from `_source` in the datastore for storage savings.
|
|
753
|
+
#
|
|
754
|
+
# @return [Boolean] true if this field's data can be returned (default: true)
|
|
755
|
+
def returnable?
|
|
756
|
+
return true if returnable.nil?
|
|
757
|
+
returnable
|
|
758
|
+
end
|
|
759
|
+
|
|
746
760
|
# Defines an argument on the field.
|
|
747
761
|
#
|
|
748
762
|
# @note ElasticGraph takes care of defining arguments for all the query features it supports, so there is generally no need to use
|
|
@@ -892,7 +906,10 @@ module ElasticGraph
|
|
|
892
906
|
parent_type: parent_type,
|
|
893
907
|
name_in_index: name_in_index,
|
|
894
908
|
type_for_derived_types: nil,
|
|
895
|
-
resolver: nil
|
|
909
|
+
resolver: nil,
|
|
910
|
+
# Filter fields should always appear in their parent input type's SDL regardless
|
|
911
|
+
# of the source field's returnability.
|
|
912
|
+
returnable: true
|
|
896
913
|
)
|
|
897
914
|
|
|
898
915
|
schema_def_state.factory.new_field(**params).tap do |f|
|
|
@@ -30,7 +30,7 @@ module ElasticGraph
|
|
|
30
30
|
include Mixins::SupportsFilteringAndAggregation
|
|
31
31
|
|
|
32
32
|
# `include HasIndices` provides the following methods:
|
|
33
|
-
# @dynamic runtime_metadata, derived_indexed_types, indices,
|
|
33
|
+
# @dynamic runtime_metadata, derived_indexed_types, indices, root_document_type?, abstract?, directly_queryable?
|
|
34
34
|
include Mixins::HasIndices
|
|
35
35
|
|
|
36
36
|
# `include ImplementsInterfaces` provides the following methods:
|
|
@@ -38,6 +38,16 @@ module ElasticGraph
|
|
|
38
38
|
include Mixins::ImplementsInterfaces
|
|
39
39
|
include Mixins::HasReadableToSAndInspect.new { |t| t.name }
|
|
40
40
|
|
|
41
|
+
# @return [Hash<String, Field>] fields that will be indexed, including __typename for mixed-type indices (types
|
|
42
|
+
# that inherit an index from an abstract supertype)
|
|
43
|
+
# @private
|
|
44
|
+
def indexing_fields_by_name_in_index
|
|
45
|
+
return super if has_own_index_def?
|
|
46
|
+
return super unless root_document_type?
|
|
47
|
+
|
|
48
|
+
super.merge("__typename" => schema_def_state.factory.new_field(name: "__typename", type: "String", parent_type: self))
|
|
49
|
+
end
|
|
50
|
+
|
|
41
51
|
# @private
|
|
42
52
|
def initialize(schema_def_state, name)
|
|
43
53
|
field_factory = schema_def_state.factory.method(:new_field)
|
|
@@ -28,7 +28,7 @@ module ElasticGraph
|
|
|
28
28
|
|
|
29
29
|
# Determines the set of sub aggregation paths for the given type.
|
|
30
30
|
def self.paths_for(type, schema_def_state:)
|
|
31
|
-
root_paths = type.
|
|
31
|
+
root_paths = type.root_document_type? ? [SubAggregationPath.new([type.name], [])] : [] # : ::Array[SubAggregationPath]
|
|
32
32
|
|
|
33
33
|
non_relation_field_refs = schema_def_state
|
|
34
34
|
.user_defined_field_references_by_type_name.fetch(type.name) { [] }
|
|
@@ -137,6 +137,9 @@ module ElasticGraph
|
|
|
137
137
|
# ElasticGraph will infer field sortability based on the field's GraphQL type and mapping type.
|
|
138
138
|
# @option options [Boolean] highlightable force-enables or disables the ability to request search highlights for this field. When
|
|
139
139
|
# not provided, ElasticGraph will infer field highlightable based on the field's mapping type.
|
|
140
|
+
# @option options [Boolean] returnable when set to `false`, the field will not appear in the GraphQL output type and its data
|
|
141
|
+
# will be excluded from `_source` in the datastore for storage savings. The field will still be available for filtering,
|
|
142
|
+
# sorting, grouping, and aggregation. Defaults to `true`.
|
|
140
143
|
# @yield [Field] the field for further customization
|
|
141
144
|
# @return [void]
|
|
142
145
|
#
|
|
@@ -470,11 +473,6 @@ module ElasticGraph
|
|
|
470
473
|
schema_def_state.type_ref("NonNumeric").as_aggregated_values
|
|
471
474
|
end
|
|
472
475
|
|
|
473
|
-
# @private
|
|
474
|
-
def indexed?
|
|
475
|
-
false
|
|
476
|
-
end
|
|
477
|
-
|
|
478
476
|
# @private
|
|
479
477
|
def to_indexing_field_type
|
|
480
478
|
Indexing::FieldType::Object.new(
|
|
@@ -536,6 +534,7 @@ module ElasticGraph
|
|
|
536
534
|
|
|
537
535
|
def fields_sdl(&arg_selector)
|
|
538
536
|
graphql_fields_by_name.values
|
|
537
|
+
.select(&:returnable?)
|
|
539
538
|
.map { |f| f.to_sdl(&arg_selector) }
|
|
540
539
|
.flat_map { |sdl| sdl.split("\n") }
|
|
541
540
|
.join("\n ")
|
|
@@ -94,6 +94,9 @@ module ElasticGraph
|
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
subtype_refs << type_ref
|
|
97
|
+
|
|
98
|
+
# Register reverse lookup so we can efficiently find which unions contain this type
|
|
99
|
+
schema_def_state.union_types_by_member_ref[type_ref] << self
|
|
97
100
|
end
|
|
98
101
|
|
|
99
102
|
# Defines multiple subtypes of this union type.
|
|
@@ -128,6 +131,15 @@ module ElasticGraph
|
|
|
128
131
|
"#{formatted_documentation}union #{name} #{directives_sdl(suffix_with: " ")}= #{subtype_refs.map(&:name).to_a.join(" | ")}"
|
|
129
132
|
end
|
|
130
133
|
|
|
134
|
+
# Union types cannot themselves be members of other unions or implement interfaces,
|
|
135
|
+
# so they have no supertypes.
|
|
136
|
+
#
|
|
137
|
+
# @return [Set] empty set
|
|
138
|
+
# @private
|
|
139
|
+
def recursively_resolve_supertypes
|
|
140
|
+
Set[]
|
|
141
|
+
end
|
|
142
|
+
|
|
131
143
|
# @private
|
|
132
144
|
def verify_graphql_correctness!
|
|
133
145
|
# Nothing to verify. `verify_graphql_correctness!` will be called on each subtype automatically.
|
|
@@ -32,6 +32,7 @@ module ElasticGraph
|
|
|
32
32
|
:scalar_types_by_name,
|
|
33
33
|
:enum_types_by_name,
|
|
34
34
|
:implementations_by_interface_ref,
|
|
35
|
+
:union_types_by_member_ref,
|
|
35
36
|
:sdl_parts,
|
|
36
37
|
:paginated_collection_element_types,
|
|
37
38
|
:user_defined_fields,
|
|
@@ -43,7 +44,7 @@ module ElasticGraph
|
|
|
43
44
|
:json_schema_version_setter_location,
|
|
44
45
|
:graphql_extension_modules,
|
|
45
46
|
:graphql_resolvers_by_name,
|
|
46
|
-
:
|
|
47
|
+
:built_in_graphql_resolvers,
|
|
47
48
|
:initially_registered_built_in_types,
|
|
48
49
|
:built_in_types_customization_blocks,
|
|
49
50
|
:user_definition_complete,
|
|
@@ -54,7 +55,8 @@ module ElasticGraph
|
|
|
54
55
|
:type_namer,
|
|
55
56
|
:enum_value_namer,
|
|
56
57
|
:allow_omitted_json_schema_fields,
|
|
57
|
-
:allow_extra_json_schema_fields
|
|
58
|
+
:allow_extra_json_schema_fields,
|
|
59
|
+
:indexed_types_by_index_name
|
|
58
60
|
)
|
|
59
61
|
include Mixins::HasReadableToSAndInspect.new
|
|
60
62
|
|
|
@@ -79,6 +81,7 @@ module ElasticGraph
|
|
|
79
81
|
scalar_types_by_name: {},
|
|
80
82
|
enum_types_by_name: {},
|
|
81
83
|
implementations_by_interface_ref: ::Hash.new { |h, k| h[k] = ::Set.new },
|
|
84
|
+
union_types_by_member_ref: ::Hash.new { |h, k| h[k] = ::Set.new },
|
|
82
85
|
sdl_parts: [],
|
|
83
86
|
paginated_collection_element_types: ::Set.new,
|
|
84
87
|
user_defined_fields: ::Set.new,
|
|
@@ -90,6 +93,7 @@ module ElasticGraph
|
|
|
90
93
|
json_schema_version: nil,
|
|
91
94
|
graphql_extension_modules: [],
|
|
92
95
|
graphql_resolvers_by_name: {},
|
|
96
|
+
built_in_graphql_resolvers: ::Set.new,
|
|
93
97
|
initially_registered_built_in_types: ::Set.new,
|
|
94
98
|
built_in_types_customization_blocks: [],
|
|
95
99
|
user_definition_complete: false,
|
|
@@ -103,7 +107,8 @@ module ElasticGraph
|
|
|
103
107
|
enum_value_namer: SchemaElements::EnumValueNamer.new(enum_value_overrides_by_type),
|
|
104
108
|
output: output,
|
|
105
109
|
allow_omitted_json_schema_fields: false,
|
|
106
|
-
allow_extra_json_schema_fields: true
|
|
110
|
+
allow_extra_json_schema_fields: true,
|
|
111
|
+
indexed_types_by_index_name: {}
|
|
107
112
|
)
|
|
108
113
|
end
|
|
109
114
|
|
|
@@ -132,6 +137,13 @@ module ElasticGraph
|
|
|
132
137
|
register_type(type)
|
|
133
138
|
end
|
|
134
139
|
|
|
140
|
+
def register_index(name, type)
|
|
141
|
+
if (existing_type = indexed_types_by_index_name[name])
|
|
142
|
+
raise Errors::SchemaError, "Duplicate index name `#{name}` defined on `#{type.name}` and `#{existing_type.name}`. Each index can only be defined once."
|
|
143
|
+
end
|
|
144
|
+
indexed_types_by_index_name[name] = type
|
|
145
|
+
end
|
|
146
|
+
|
|
135
147
|
def register_renamed_type(type_name, from:, defined_at:, defined_via:)
|
|
136
148
|
renamed_types_by_old_name[from] = factory.new_deprecated_element(
|
|
137
149
|
type_name,
|
|
@@ -185,8 +197,8 @@ module ElasticGraph
|
|
|
185
197
|
@factory ||= Factory.new(self)
|
|
186
198
|
end
|
|
187
199
|
|
|
188
|
-
def
|
|
189
|
-
@
|
|
200
|
+
def enums_for_directly_queryable_types
|
|
201
|
+
@enums_for_directly_queryable_types ||= factory.new_enums_for_directly_queryable_types
|
|
190
202
|
end
|
|
191
203
|
|
|
192
204
|
def sub_aggregation_paths_for(type)
|