elasticgraph-schema_definition 0.18.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|