elasticgraph-schema_definition 0.18.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +7 -0
- data/elasticgraph-schema_definition.gemspec +26 -0
- data/lib/elastic_graph/schema_definition/api.rb +359 -0
- data/lib/elastic_graph/schema_definition/factory.rb +506 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb +79 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb +59 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb +99 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb +62 -0
- data/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb +346 -0
- data/lib/elastic_graph/schema_definition/indexing/event_envelope.rb +74 -0
- data/lib/elastic_graph/schema_definition/indexing/field.rb +181 -0
- data/lib/elastic_graph/schema_definition/indexing/field_reference.rb +51 -0
- data/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb +65 -0
- data/lib/elastic_graph/schema_definition/indexing/field_type/object.rb +113 -0
- data/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb +51 -0
- data/lib/elastic_graph/schema_definition/indexing/field_type/union.rb +70 -0
- data/lib/elastic_graph/schema_definition/indexing/index.rb +318 -0
- data/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb +34 -0
- data/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb +234 -0
- data/lib/elastic_graph/schema_definition/indexing/list_counts_mapping.rb +53 -0
- data/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb +96 -0
- data/lib/elastic_graph/schema_definition/indexing/rollover_config.rb +25 -0
- data/lib/elastic_graph/schema_definition/indexing/update_target_factory.rb +54 -0
- data/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb +195 -0
- data/lib/elastic_graph/schema_definition/json_schema_pruner.rb +61 -0
- data/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb +31 -0
- data/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb +119 -0
- data/lib/elastic_graph/schema_definition/mixins/has_directives.rb +65 -0
- data/lib/elastic_graph/schema_definition/mixins/has_documentation.rb +74 -0
- data/lib/elastic_graph/schema_definition/mixins/has_indices.rb +281 -0
- data/lib/elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect.rb +46 -0
- data/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb +116 -0
- data/lib/elastic_graph/schema_definition/mixins/has_type_info.rb +181 -0
- data/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb +122 -0
- data/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb +47 -0
- data/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb +267 -0
- data/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb +38 -0
- data/lib/elastic_graph/schema_definition/rake_tasks.rb +190 -0
- data/lib/elastic_graph/schema_definition/results.rb +404 -0
- data/lib/elastic_graph/schema_definition/schema_artifact_manager.rb +482 -0
- data/lib/elastic_graph/schema_definition/schema_elements/argument.rb +56 -0
- data/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb +1541 -0
- data/lib/elastic_graph/schema_definition/schema_elements/deprecated_element.rb +21 -0
- data/lib/elastic_graph/schema_definition/schema_elements/directive.rb +40 -0
- data/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb +189 -0
- data/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb +73 -0
- data/lib/elastic_graph/schema_definition/schema_elements/enum_value_namer.rb +89 -0
- data/lib/elastic_graph/schema_definition/schema_elements/enums_for_indexed_types.rb +82 -0
- data/lib/elastic_graph/schema_definition/schema_elements/field.rb +1085 -0
- data/lib/elastic_graph/schema_definition/schema_elements/field_path.rb +112 -0
- data/lib/elastic_graph/schema_definition/schema_elements/field_source.rb +16 -0
- data/lib/elastic_graph/schema_definition/schema_elements/graphql_sdl_enumerator.rb +113 -0
- data/lib/elastic_graph/schema_definition/schema_elements/input_field.rb +31 -0
- data/lib/elastic_graph/schema_definition/schema_elements/input_type.rb +60 -0
- data/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb +72 -0
- data/lib/elastic_graph/schema_definition/schema_elements/list_counts_state.rb +40 -0
- data/lib/elastic_graph/schema_definition/schema_elements/object_type.rb +53 -0
- data/lib/elastic_graph/schema_definition/schema_elements/relationship.rb +218 -0
- data/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb +310 -0
- data/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb +36 -0
- data/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.rb +66 -0
- data/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb +237 -0
- data/lib/elastic_graph/schema_definition/schema_elements/type_reference.rb +353 -0
- data/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb +579 -0
- data/lib/elastic_graph/schema_definition/schema_elements/union_type.rb +157 -0
- data/lib/elastic_graph/schema_definition/scripting/file_system_repository.rb +77 -0
- data/lib/elastic_graph/schema_definition/scripting/script.rb +48 -0
- data/lib/elastic_graph/schema_definition/scripting/scripts/field/as_day_of_week.painless +24 -0
- data/lib/elastic_graph/schema_definition/scripting/scripts/field/as_time_of_day.painless +41 -0
- data/lib/elastic_graph/schema_definition/scripting/scripts/filter/by_time_of_day.painless +22 -0
- data/lib/elastic_graph/schema_definition/scripting/scripts/update/index_data.painless +93 -0
- data/lib/elastic_graph/schema_definition/state.rb +212 -0
- data/lib/elastic_graph/schema_definition/test_support.rb +113 -0
- metadata +513 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
module ElasticGraph
|
10
|
+
module SchemaDefinition
|
11
|
+
module SchemaElements
|
12
|
+
# @private
|
13
|
+
DeprecatedElement = ::Data.define(:schema_def_state, :name, :defined_at, :defined_via) do
|
14
|
+
# @implements DeprecatedElement
|
15
|
+
def description
|
16
|
+
"`#{defined_via}` at #{defined_at.path}:#{defined_at.lineno}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "elastic_graph/schema_definition/mixins/verifies_graphql_name"
|
10
|
+
require "elastic_graph/support/graphql_formatter"
|
11
|
+
|
12
|
+
module ElasticGraph
|
13
|
+
module SchemaDefinition
|
14
|
+
module SchemaElements
|
15
|
+
# Represents a [GraphQL directive](https://spec.graphql.org/October2021/#sec-Language.Directives).
|
16
|
+
#
|
17
|
+
# @!attribute [r] name
|
18
|
+
# @return [String] name of the directive
|
19
|
+
# @!attribute [r] arguments
|
20
|
+
# @return [Hash<Symbol, Object>] directive arguments
|
21
|
+
# @!parse class Directive < ::Data; end
|
22
|
+
class Directive < ::Data.define(:name, :arguments)
|
23
|
+
prepend Mixins::VerifiesGraphQLName
|
24
|
+
|
25
|
+
# @return [String] GraphQL SDL form of the directive
|
26
|
+
def to_sdl
|
27
|
+
%(@#{name}#{Support::GraphQLFormatter.format_args(**arguments)})
|
28
|
+
end
|
29
|
+
|
30
|
+
# Duplicates this directive on another GraphQL schema element.
|
31
|
+
#
|
32
|
+
# @param element [Argument, EnumType, EnumValue, Field, ScalarType, TypeWithSubfields, UnionType] schema element
|
33
|
+
# @return [void]
|
34
|
+
def duplicate_on(element)
|
35
|
+
element.directive name, arguments
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "elastic_graph/schema_artifacts/runtime_metadata/enum"
|
10
|
+
require "elastic_graph/schema_definition/indexing/field_type/enum"
|
11
|
+
require "elastic_graph/schema_definition/mixins/can_be_graphql_only"
|
12
|
+
require "elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations"
|
13
|
+
require "elastic_graph/schema_definition/mixins/has_directives"
|
14
|
+
require "elastic_graph/schema_definition/mixins/has_documentation"
|
15
|
+
require "elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect"
|
16
|
+
require "elastic_graph/schema_definition/mixins/verifies_graphql_name"
|
17
|
+
|
18
|
+
module ElasticGraph
|
19
|
+
module SchemaDefinition
|
20
|
+
module SchemaElements
|
21
|
+
# {include:API#enum_type}
|
22
|
+
#
|
23
|
+
# @example Define an enum type
|
24
|
+
# ElasticGraph.define_schema do |schema|
|
25
|
+
# schema.enum_type "Currency" do |t|
|
26
|
+
# # in the block, `t` is an EnumType
|
27
|
+
# t.value "USD"
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# @!attribute [r] schema_def_state
|
32
|
+
# @return [State] state of the schema
|
33
|
+
# @!attribute [rw] type_ref
|
34
|
+
# @private
|
35
|
+
# @!attribute [rw] for_output
|
36
|
+
# @return [Boolean] `true` if this enum is used for both input and output; `false` if it is for input only
|
37
|
+
# @!attribute [r] values_by_name
|
38
|
+
# @return [Hash<String, EnumValue>] map of enum values, keyed by name
|
39
|
+
class EnumType < Struct.new(:schema_def_state, :type_ref, :for_output, :values_by_name)
|
40
|
+
# @dynamic type_ref, graphql_only?
|
41
|
+
prepend Mixins::VerifiesGraphQLName
|
42
|
+
include Mixins::CanBeGraphQLOnly
|
43
|
+
include Mixins::HasDocumentation
|
44
|
+
include Mixins::HasDirectives
|
45
|
+
include Mixins::HasDerivedGraphQLTypeCustomizations
|
46
|
+
include Mixins::HasReadableToSAndInspect.new { |e| e.name }
|
47
|
+
|
48
|
+
# @private
|
49
|
+
def initialize(schema_def_state, name)
|
50
|
+
# @type var values_by_name: ::Hash[::String, EnumValue]
|
51
|
+
values_by_name = {}
|
52
|
+
super(schema_def_state, schema_def_state.type_ref(name).to_final_form, true, values_by_name)
|
53
|
+
|
54
|
+
# :nocov: -- currently all invocations have a block
|
55
|
+
yield self if block_given?
|
56
|
+
# :nocov:
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [String] name of the enum type
|
60
|
+
def name
|
61
|
+
type_ref.name
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [TypeReference] reference to `AggregatedValues` type to use for this enum.
|
65
|
+
def aggregated_values_type
|
66
|
+
schema_def_state.type_ref("NonNumeric").as_aggregated_values
|
67
|
+
end
|
68
|
+
|
69
|
+
# Defines an enum value for the current enum type.
|
70
|
+
#
|
71
|
+
# @param value_name [String] name of the enum value
|
72
|
+
# @yield [EnumValue] enum value so it can be further customized
|
73
|
+
# @return [void]
|
74
|
+
#
|
75
|
+
# @example Define an enum type with multiple enum values
|
76
|
+
# ElasticGraph.define_schema do |schema|
|
77
|
+
# schema.enum_type "Currency" do |t|
|
78
|
+
# t.value "USD" do |v|
|
79
|
+
# v.documentation "US Dollars."
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# t.value "JPY" do |v|
|
83
|
+
# v.documentation "Japanese Yen."
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
# end
|
87
|
+
def value(value_name, &block)
|
88
|
+
alternate_original_name = value_name
|
89
|
+
value_name = schema_def_state.enum_value_namer.name_for(name, value_name.to_s)
|
90
|
+
|
91
|
+
if values_by_name.key?(value_name)
|
92
|
+
raise SchemaError, "Duplicate value on Enum::Type #{name}: #{value_name}"
|
93
|
+
end
|
94
|
+
|
95
|
+
if value_name.length > DEFAULT_MAX_KEYWORD_LENGTH
|
96
|
+
raise SchemaError, "Enum value `#{name}.#{value_name}` is too long: it is #{value_name.length} characters but cannot exceed #{DEFAULT_MAX_KEYWORD_LENGTH} characters."
|
97
|
+
end
|
98
|
+
|
99
|
+
values_by_name[value_name] = schema_def_state.factory.new_enum_value(value_name, alternate_original_name, &block)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Defines multiple enum values. In contrast to {#value}, the enum values cannot be customized
|
103
|
+
# further via a block.
|
104
|
+
#
|
105
|
+
# @param value_names [Array<String>] names of the enum values
|
106
|
+
# @return [void]
|
107
|
+
#
|
108
|
+
# @example Define an enum type with multiple enum values
|
109
|
+
# ElasticGraph.define_schema do |schema|
|
110
|
+
# schema.enum_type "Currency" do |t|
|
111
|
+
# t.values "USD", "JPY", "CAD", "GBP"
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
def values(*value_names)
|
115
|
+
value_names.flatten.each { |name| value(name) }
|
116
|
+
end
|
117
|
+
|
118
|
+
# @return [SchemaArtifacts::RuntimeMetadata::Enum::Type] runtime metadata for this enum type
|
119
|
+
def runtime_metadata
|
120
|
+
runtime_metadata_values_by_name = values_by_name
|
121
|
+
.transform_values(&:runtime_metadata)
|
122
|
+
.compact
|
123
|
+
|
124
|
+
SchemaArtifacts::RuntimeMetadata::Enum::Type.new(values_by_name: runtime_metadata_values_by_name)
|
125
|
+
end
|
126
|
+
|
127
|
+
# @return [String] GraphQL SDL form of the enum type
|
128
|
+
def to_sdl
|
129
|
+
if values_by_name.empty?
|
130
|
+
raise SchemaError, "Enum type #{name} has no values, but enums must have at least one value."
|
131
|
+
end
|
132
|
+
|
133
|
+
<<~EOS
|
134
|
+
#{formatted_documentation}enum #{name} #{directives_sdl(suffix_with: " ")}{
|
135
|
+
#{values_by_name.values.map(&:to_sdl).flat_map { |s| s.split("\n") }.join("\n ")}
|
136
|
+
}
|
137
|
+
EOS
|
138
|
+
end
|
139
|
+
|
140
|
+
# @private
|
141
|
+
def derived_graphql_types
|
142
|
+
# Derived GraphQL types must be generated for an output enum. For an enum type that is only
|
143
|
+
# used as an input, we do not need derived types.
|
144
|
+
return [] unless for_output
|
145
|
+
|
146
|
+
derived_scalar_types = schema_def_state.factory.new_scalar_type(name) do |t|
|
147
|
+
t.mapping type: "keyword"
|
148
|
+
t.json_schema type: "string"
|
149
|
+
t.graphql_only graphql_only?
|
150
|
+
end.derived_graphql_types
|
151
|
+
|
152
|
+
if (input_enum = as_input).equal?(self)
|
153
|
+
derived_scalar_types
|
154
|
+
else
|
155
|
+
[input_enum] + derived_scalar_types
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [Indexing::FieldType::Enum] indexing representation of this enum type
|
160
|
+
def to_indexing_field_type
|
161
|
+
Indexing::FieldType::Enum.new(values_by_name.keys)
|
162
|
+
end
|
163
|
+
|
164
|
+
# @return [false] enum types are never directly indexed
|
165
|
+
def indexed?
|
166
|
+
false
|
167
|
+
end
|
168
|
+
|
169
|
+
# @return [EnumType] converts the enum type to its input form for when different naming is used for input vs output enums.
|
170
|
+
def as_input
|
171
|
+
input_name = type_ref
|
172
|
+
.as_input_enum # To apply the configured format for input enums.
|
173
|
+
.to_final_form # To handle a type name override of the input enum.
|
174
|
+
.name
|
175
|
+
|
176
|
+
return self if input_name == name
|
177
|
+
|
178
|
+
schema_def_state.factory.new_enum_type(input_name) do |t|
|
179
|
+
t.for_output = false # flag that it's not used as an output enum, and therefore `derived_graphql_types` will be empty on it.
|
180
|
+
t.graphql_only true # input enums are always GraphQL-only.
|
181
|
+
t.documentation doc_comment
|
182
|
+
directives.each { |dir| dir.duplicate_on(t) }
|
183
|
+
values_by_name.each { |_, val| val.duplicate_on(t) }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "elastic_graph/schema_definition/mixins/has_directives"
|
10
|
+
require "elastic_graph/schema_definition/mixins/has_documentation"
|
11
|
+
require "elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect"
|
12
|
+
require "elastic_graph/schema_definition/mixins/verifies_graphql_name"
|
13
|
+
|
14
|
+
module ElasticGraph
|
15
|
+
module SchemaDefinition
|
16
|
+
module SchemaElements
|
17
|
+
# Represents a value of a [GraphQL enum type](https://spec.graphql.org/October2021/#sec-Enums).
|
18
|
+
#
|
19
|
+
# @!attribute [r] schema_def_state
|
20
|
+
# @return [State] state of the schema
|
21
|
+
# @!attribute [r] name
|
22
|
+
# @return [String] name of the value
|
23
|
+
# @!attribute [r] runtime_metadata
|
24
|
+
# @return [SchemaElements::RuntimeMetadata::Enum::Value] runtime metadata
|
25
|
+
class EnumValue < Struct.new(:schema_def_state, :name, :runtime_metadata)
|
26
|
+
prepend Mixins::VerifiesGraphQLName
|
27
|
+
include Mixins::HasDocumentation
|
28
|
+
include Mixins::HasDirectives
|
29
|
+
include Mixins::HasReadableToSAndInspect.new { |v| v.name }
|
30
|
+
|
31
|
+
# @private
|
32
|
+
def initialize(schema_def_state, name, original_name)
|
33
|
+
runtime_metadata = SchemaArtifacts::RuntimeMetadata::Enum::Value.new(
|
34
|
+
sort_field: nil,
|
35
|
+
datastore_value: nil,
|
36
|
+
datastore_abbreviation: nil,
|
37
|
+
alternate_original_name: (original_name if original_name != name)
|
38
|
+
)
|
39
|
+
|
40
|
+
super(schema_def_state, name, runtime_metadata)
|
41
|
+
yield self
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [String] GraphQL SDL form of the enum value
|
45
|
+
def to_sdl
|
46
|
+
"#{formatted_documentation}#{name}#{directives_sdl(prefix_with: " ")}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Duplicates this enum value on another {EnumType}.
|
50
|
+
#
|
51
|
+
# @param other_enum_type [EnumType] enum type to duplicate this value onto
|
52
|
+
# @return [void]
|
53
|
+
def duplicate_on(other_enum_type)
|
54
|
+
other_enum_type.value name do |v|
|
55
|
+
v.documentation doc_comment
|
56
|
+
directives.each { |dir| dir.duplicate_on(v) }
|
57
|
+
v.update_runtime_metadata(**runtime_metadata.to_h)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Updates the runtime metadata.
|
62
|
+
#
|
63
|
+
# @param [Hash<Symbol, Object>] updates to apply to the runtime metadata
|
64
|
+
# @return [void]
|
65
|
+
def update_runtime_metadata(**updates)
|
66
|
+
self.runtime_metadata = runtime_metadata.with(**updates)
|
67
|
+
end
|
68
|
+
|
69
|
+
private :runtime_metadata=
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "elastic_graph/constants"
|
10
|
+
require "elastic_graph/error"
|
11
|
+
require "elastic_graph/support/hash_util"
|
12
|
+
|
13
|
+
module ElasticGraph
|
14
|
+
module SchemaDefinition
|
15
|
+
module SchemaElements
|
16
|
+
# Abstraction for generating names for GraphQL enum values. This allows users to customize the
|
17
|
+
# naming of our built-in enum values.
|
18
|
+
#
|
19
|
+
# @private
|
20
|
+
class EnumValueNamer < ::Struct.new(:overrides_by_type_name)
|
21
|
+
def initialize(overrides_by_type_name = {})
|
22
|
+
overrides_by_type_name = Support::HashUtil
|
23
|
+
.stringify_keys(overrides_by_type_name) # : ::Hash[::String, ::Hash[::String, ::String]]
|
24
|
+
|
25
|
+
@used_value_names_by_type_name = ::Hash.new { |h, k| h[k] = [] }
|
26
|
+
validate_overrides(overrides_by_type_name)
|
27
|
+
super(overrides_by_type_name: overrides_by_type_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the name that should be used for the given `type_name` and `value_name`.
|
31
|
+
def name_for(type_name, value_name)
|
32
|
+
@used_value_names_by_type_name[type_name] << value_name
|
33
|
+
overrides_by_type_name.dig(type_name, value_name) || value_name
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the overrides that did not wind up being used. Unused overrides usually happen
|
37
|
+
# because of a typo, and can be safely removed.
|
38
|
+
def unused_overrides
|
39
|
+
overrides_by_type_name.filter_map do |type_name, overrides|
|
40
|
+
if @used_value_names_by_type_name.key?(type_name)
|
41
|
+
unused_overrides = overrides.except(*@used_value_names_by_type_name.fetch(type_name))
|
42
|
+
[type_name, unused_overrides] unless unused_overrides.empty?
|
43
|
+
else
|
44
|
+
[type_name, overrides]
|
45
|
+
end
|
46
|
+
end.to_h
|
47
|
+
end
|
48
|
+
|
49
|
+
# Full set of enum type and value names that were used. Can be used to provide suggestions
|
50
|
+
# for when there are `unused_overrides`.
|
51
|
+
def used_value_names_by_type_name
|
52
|
+
@used_value_names_by_type_name.dup
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def validate_overrides(overrides_by_type_name)
|
58
|
+
duplicate_problems = overrides_by_type_name.flat_map do |type_name, overrides|
|
59
|
+
overrides
|
60
|
+
.group_by { |k, v| v }
|
61
|
+
.transform_values { |kv_pairs| kv_pairs.map(&:first) }
|
62
|
+
.select { |_, v| v.size > 1 }
|
63
|
+
.map do |override, source_names|
|
64
|
+
"Multiple `#{type_name}` enum value overrides (#{source_names.sort.join(", ")}) map to the same name (#{override}), which is not supported."
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
invalid_name_problems = overrides_by_type_name.flat_map do |type_name, overrides|
|
69
|
+
overrides.filter_map do |source_name, override|
|
70
|
+
unless GRAPHQL_NAME_PATTERN.match(override)
|
71
|
+
"`#{override}` (the override for `#{type_name}.#{source_name}`) is not a valid GraphQL type name. " +
|
72
|
+
GRAPHQL_NAME_VALIDITY_DESCRIPTION
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
notify_problems(duplicate_problems + invalid_name_problems)
|
78
|
+
end
|
79
|
+
|
80
|
+
def notify_problems(problems)
|
81
|
+
return if problems.empty?
|
82
|
+
|
83
|
+
raise ConfigError, "Provided `enum_value_overrides_by_type_name` have #{problems.size} problem(s):\n\n" \
|
84
|
+
"#{problems.map.with_index(1) { |problem, i| "#{i}. #{problem}" }.join("\n\n")}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "elastic_graph/schema_artifacts/runtime_metadata/enum"
|
10
|
+
require "elastic_graph/schema_artifacts/runtime_metadata/sort_field"
|
11
|
+
|
12
|
+
module ElasticGraph
|
13
|
+
module SchemaDefinition
|
14
|
+
module SchemaElements
|
15
|
+
# Responsible for generating enum types based on specific indexed types.
|
16
|
+
#
|
17
|
+
# @private
|
18
|
+
class EnumsForIndexedTypes
|
19
|
+
def initialize(schema_def_state)
|
20
|
+
@schema_def_state = schema_def_state
|
21
|
+
end
|
22
|
+
|
23
|
+
# Generates a `SortOrder` enum type for the given indexed type.
|
24
|
+
def sort_order_enum_for(indexed_type)
|
25
|
+
return nil unless indexed_type.indexed?
|
26
|
+
|
27
|
+
build_enum(indexed_type, :sort_order, :sortable?, "sorted") do |enum_type, field_path|
|
28
|
+
value_name_parts = field_path.map(&:name)
|
29
|
+
index_field = field_path.map(&:name_in_index).join(".")
|
30
|
+
|
31
|
+
{asc: "ascending", desc: "descending"}.each do |dir, dir_description|
|
32
|
+
enum_type.value((value_name_parts + [dir.to_s.upcase]).join("_")) do |v|
|
33
|
+
v.update_runtime_metadata sort_field: SchemaArtifacts::RuntimeMetadata::SortField.new(index_field, dir)
|
34
|
+
v.documentation "Sorts #{dir_description} by the `#{graphql_field_path_description(field_path)}` field."
|
35
|
+
|
36
|
+
wrapped_enum_value = @schema_def_state.factory.new_sort_order_enum_value(v, field_path)
|
37
|
+
|
38
|
+
field_path.each do |field|
|
39
|
+
field.sort_order_enum_value_customizations.each { |block| block.call(wrapped_enum_value) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def build_enum(indexed_type, category, field_predicate, past_tense_verb, &block)
|
49
|
+
derived_type_ref = indexed_type.type_ref.as_static_derived_type(category)
|
50
|
+
|
51
|
+
enum = @schema_def_state.factory.new_enum_type(derived_type_ref.name) do |enum_type|
|
52
|
+
enum_type.documentation "Enumerates the ways `#{indexed_type.name}`s can be #{past_tense_verb}."
|
53
|
+
define_enum_values_for_type(enum_type, indexed_type, field_predicate, &block)
|
54
|
+
end.as_input
|
55
|
+
|
56
|
+
enum unless enum.values_by_name.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def define_enum_values_for_type(enum_type, object_type, field_predicate, parents: [], &block)
|
60
|
+
object_type
|
61
|
+
.graphql_fields_by_name.values
|
62
|
+
.select(&field_predicate)
|
63
|
+
.each { |f| define_enum_values_for_field(enum_type, f, field_predicate, parents: parents, &block) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def define_enum_values_for_field(enum_type, field, field_predicate, parents:, &block)
|
67
|
+
path = parents + [field]
|
68
|
+
|
69
|
+
if (object_type = field.type.fully_unwrapped.as_object_type)
|
70
|
+
define_enum_values_for_type(enum_type, object_type, field_predicate, parents: path, &block)
|
71
|
+
else
|
72
|
+
block.call(enum_type, path)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def graphql_field_path_description(field_path)
|
77
|
+
field_path.map(&:name).join(".")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|