elasticgraph-graphql 0.19.1.1 → 0.19.2.1
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/graphql/aggregation/composite_grouping_adapter.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/computation.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/date_histogram_grouping.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/field_path_encoder.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/field_term_grouping.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/key.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/nested_sub_aggregation.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/non_composite_grouping_adapter.rb +2 -2
- data/lib/elastic_graph/graphql/aggregation/path_segment.rb +2 -2
- data/lib/elastic_graph/graphql/aggregation/query.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/query_adapter.rb +33 -6
- data/lib/elastic_graph/graphql/aggregation/query_optimizer.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/resolvers/aggregated_values.rb +2 -6
- data/lib/elastic_graph/graphql/aggregation/resolvers/count_detail.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/resolvers/grouped_by.rb +26 -6
- data/lib/elastic_graph/graphql/aggregation/resolvers/node.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/resolvers/relay_connection_builder.rb +5 -6
- data/lib/elastic_graph/graphql/aggregation/resolvers/sub_aggregations.rb +10 -8
- data/lib/elastic_graph/graphql/aggregation/script_term_grouping.rb +1 -1
- data/lib/elastic_graph/graphql/aggregation/term_grouping.rb +2 -2
- data/lib/elastic_graph/graphql/client.rb +1 -1
- data/lib/elastic_graph/graphql/config.rb +21 -6
- data/lib/elastic_graph/graphql/datastore_query/document_paginator.rb +10 -5
- data/lib/elastic_graph/graphql/datastore_query/index_expression_builder.rb +2 -3
- data/lib/elastic_graph/graphql/datastore_query/paginator.rb +1 -1
- data/lib/elastic_graph/graphql/datastore_query/routing_picker.rb +2 -3
- data/lib/elastic_graph/graphql/datastore_query.rb +66 -74
- data/lib/elastic_graph/graphql/datastore_response/document.rb +1 -1
- data/lib/elastic_graph/graphql/datastore_response/search_response.rb +83 -9
- data/lib/elastic_graph/graphql/datastore_search_router.rb +19 -4
- data/lib/elastic_graph/graphql/decoded_cursor.rb +1 -1
- data/lib/elastic_graph/graphql/filtering/boolean_query.rb +1 -1
- data/lib/elastic_graph/graphql/filtering/field_path.rb +1 -1
- data/lib/elastic_graph/graphql/filtering/filter_args_translator.rb +2 -2
- data/lib/elastic_graph/graphql/filtering/filter_interpreter.rb +10 -5
- data/lib/elastic_graph/graphql/filtering/filter_node_interpreter.rb +2 -2
- data/lib/elastic_graph/graphql/filtering/filter_value_set_extractor.rb +17 -2
- data/lib/elastic_graph/graphql/filtering/range_query.rb +1 -1
- data/lib/elastic_graph/graphql/http_endpoint.rb +2 -2
- data/lib/elastic_graph/graphql/query_adapter/filters.rb +1 -1
- data/lib/elastic_graph/graphql/query_adapter/pagination.rb +1 -1
- data/lib/elastic_graph/graphql/query_adapter/requested_fields.rb +18 -3
- data/lib/elastic_graph/graphql/query_adapter/sort.rb +1 -1
- data/lib/elastic_graph/graphql/query_details_tracker.rb +11 -14
- data/lib/elastic_graph/graphql/query_executor.rb +10 -16
- data/lib/elastic_graph/graphql/resolvers/get_record_field_value.rb +6 -12
- data/lib/elastic_graph/graphql/resolvers/graphql_adapter_builder.rb +126 -0
- data/lib/elastic_graph/graphql/resolvers/list_records.rb +4 -4
- data/lib/elastic_graph/graphql/resolvers/nested_relationships.rb +57 -27
- data/lib/elastic_graph/graphql/resolvers/nested_relationships_source.rb +325 -0
- data/lib/elastic_graph/graphql/resolvers/object.rb +36 -0
- data/lib/elastic_graph/graphql/resolvers/query_adapter.rb +2 -2
- data/lib/elastic_graph/graphql/resolvers/query_source.rb +6 -3
- data/lib/elastic_graph/graphql/resolvers/relay_connection/array_adapter.rb +1 -1
- data/lib/elastic_graph/graphql/resolvers/relay_connection/generic_adapter.rb +1 -1
- data/lib/elastic_graph/graphql/resolvers/relay_connection/page_info.rb +1 -1
- data/lib/elastic_graph/graphql/resolvers/relay_connection/search_response_adapter_builder.rb +1 -1
- data/lib/elastic_graph/graphql/resolvers/relay_connection.rb +2 -2
- data/lib/elastic_graph/graphql/resolvers/resolvable_value.rb +2 -7
- data/lib/elastic_graph/graphql/scalar_coercion_adapters/cursor.rb +1 -1
- data/lib/elastic_graph/graphql/scalar_coercion_adapters/date.rb +1 -1
- data/lib/elastic_graph/graphql/scalar_coercion_adapters/date_time.rb +1 -1
- data/lib/elastic_graph/graphql/scalar_coercion_adapters/local_time.rb +1 -1
- data/lib/elastic_graph/graphql/scalar_coercion_adapters/longs.rb +1 -1
- data/lib/elastic_graph/graphql/scalar_coercion_adapters/no_op.rb +1 -1
- data/lib/elastic_graph/graphql/scalar_coercion_adapters/time_zone.rb +1 -1
- data/lib/elastic_graph/graphql/scalar_coercion_adapters/untyped.rb +1 -1
- data/lib/elastic_graph/graphql/scalar_coercion_adapters/valid_time_zones.rb +1 -1
- data/lib/elastic_graph/graphql/schema/arguments.rb +1 -1
- data/lib/elastic_graph/graphql/schema/enum_value.rb +1 -1
- data/lib/elastic_graph/graphql/schema/field.rb +12 -27
- data/lib/elastic_graph/graphql/schema/relation_join.rb +17 -9
- data/lib/elastic_graph/graphql/schema/type.rb +19 -8
- data/lib/elastic_graph/graphql/schema.rb +83 -29
- data/lib/elastic_graph/graphql.rb +56 -43
- data/script/dump_time_zones +1 -1
- metadata +59 -29
- data/lib/elastic_graph/graphql/monkey_patches/schema_field.rb +0 -56
- data/lib/elastic_graph/graphql/monkey_patches/schema_object.rb +0 -48
- data/lib/elastic_graph/graphql/resolvers/graphql_adapter.rb +0 -114
@@ -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
|
@@ -63,21 +63,25 @@ module ElasticGraph
|
|
63
63
|
|
64
64
|
# Normalizes the given documents, ensuring it has the expected cardinality.
|
65
65
|
def normalize_documents(response, &handle_warning)
|
66
|
-
doc_cardinality.normalize(response, handle_warning: handle_warning
|
66
|
+
doc_cardinality.normalize(response, handle_warning: handle_warning) { |doc| (_ = doc).id }
|
67
67
|
end
|
68
68
|
|
69
69
|
private
|
70
70
|
|
71
71
|
def normalize_ids(id_or_ids, &handle_warning)
|
72
|
-
id_cardinality.normalize(id_or_ids, handle_warning: handle_warning
|
72
|
+
id_cardinality.normalize(id_or_ids, handle_warning: handle_warning) { |id| id }
|
73
73
|
end
|
74
74
|
|
75
75
|
module Cardinality
|
76
76
|
module Many
|
77
77
|
def self.normalize(list_or_scalar, handle_warning:)
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
case list_or_scalar
|
79
|
+
when ::Enumerable
|
80
|
+
list_or_scalar
|
81
|
+
else
|
82
|
+
handle_warning.call("scalar instead of a list")
|
83
|
+
Array(list_or_scalar)
|
84
|
+
end
|
81
85
|
end
|
82
86
|
|
83
87
|
def self.blank_value
|
@@ -87,9 +91,13 @@ module ElasticGraph
|
|
87
91
|
|
88
92
|
module One
|
89
93
|
def self.normalize(list_or_scalar, handle_warning:, &deterministic_comparator)
|
90
|
-
|
91
|
-
|
92
|
-
|
94
|
+
case list_or_scalar
|
95
|
+
when ::Enumerable
|
96
|
+
handle_warning.call("list of more than one item instead of a scalar") if (_ = list_or_scalar).size > 1
|
97
|
+
list_or_scalar.min_by(&deterministic_comparator)
|
98
|
+
else
|
99
|
+
list_or_scalar
|
100
|
+
end
|
93
101
|
end
|
94
102
|
|
95
103
|
def self.blank_value
|
@@ -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
|
@@ -24,7 +24,8 @@ module ElasticGraph
|
|
24
24
|
graphql_type,
|
25
25
|
index_definitions,
|
26
26
|
object_runtime_metadata,
|
27
|
-
enum_runtime_metadata
|
27
|
+
enum_runtime_metadata,
|
28
|
+
resolvers_needing_lookahead
|
28
29
|
)
|
29
30
|
@schema = schema
|
30
31
|
@graphql_type = graphql_type
|
@@ -37,6 +38,7 @@ module ElasticGraph
|
|
37
38
|
@elasticgraph_category = object_runtime_metadata&.elasticgraph_category
|
38
39
|
@graphql_only_return_type = object_runtime_metadata&.graphql_only_return_type
|
39
40
|
@enum_runtime_metadata = enum_runtime_metadata
|
41
|
+
@resolvers_needing_lookahead = resolvers_needing_lookahead
|
40
42
|
@enum_value_names_by_original_name = (enum_runtime_metadata&.values_by_name || {}).to_h do |name, value|
|
41
43
|
[value.alternate_original_name || name, name]
|
42
44
|
end
|
@@ -45,7 +47,7 @@ module ElasticGraph
|
|
45
47
|
end
|
46
48
|
|
47
49
|
def name
|
48
|
-
@name ||= @graphql_type.to_type_signature
|
50
|
+
@name ||= @graphql_type.to_type_signature
|
49
51
|
end
|
50
52
|
|
51
53
|
# List of index definitions that should be searched for this type.
|
@@ -110,11 +112,14 @@ module ElasticGraph
|
|
110
112
|
# Returns the subtypes of this type, if it has any. This is like `#possible_types` provided by the
|
111
113
|
# GraphQL gem, but that includes a type itself when you ask for the possible types of a non-abstract type.
|
112
114
|
def subtypes
|
113
|
-
@subtypes ||= @schema
|
115
|
+
@subtypes ||= @schema
|
116
|
+
.graphql_schema
|
117
|
+
.possible_types(graphql_type, visibility_profile: :boot)
|
118
|
+
.map { |t| @schema.type_from(t) } - [self]
|
114
119
|
end
|
115
120
|
|
116
121
|
def field_named(field_name)
|
117
|
-
@fields_by_name.fetch(field_name
|
122
|
+
@fields_by_name.fetch(field_name)
|
118
123
|
rescue KeyError => e
|
119
124
|
msg = "No field named #{field_name} (on type #{name}) could be found"
|
120
125
|
msg += "; Possible alternatives: [#{e.corrections.join(", ").delete('"')}]." if e.corrections.any?
|
@@ -122,7 +127,7 @@ module ElasticGraph
|
|
122
127
|
end
|
123
128
|
|
124
129
|
def enum_value_named(enum_value_name)
|
125
|
-
@enum_values_by_name[enum_value_name
|
130
|
+
@enum_values_by_name[enum_value_name]
|
126
131
|
end
|
127
132
|
|
128
133
|
def coerce_result(result)
|
@@ -226,7 +231,7 @@ module ElasticGraph
|
|
226
231
|
graphql_enum_value = @graphql_type.values.fetch(enum_value_name)
|
227
232
|
|
228
233
|
EnumValue.new(
|
229
|
-
name: graphql_enum_value.graphql_name
|
234
|
+
name: graphql_enum_value.graphql_name,
|
230
235
|
type: self,
|
231
236
|
runtime_metadata: @enum_runtime_metadata&.values_by_name&.dig(enum_value_name)
|
232
237
|
)
|
@@ -250,7 +255,13 @@ module ElasticGraph
|
|
250
255
|
# Eagerly fan out and instantiate all `Field` objects so that the :extras
|
251
256
|
# get added to each field as require before we execute the first query
|
252
257
|
fields_hash.each_with_object({}) do |(name, field), hash|
|
253
|
-
hash[name] = Field.new(
|
258
|
+
hash[name] = Field.new(
|
259
|
+
schema,
|
260
|
+
self,
|
261
|
+
field,
|
262
|
+
@object_runtime_metadata&.graphql_fields_by_name&.dig(name),
|
263
|
+
@resolvers_needing_lookahead
|
264
|
+
)
|
254
265
|
end
|
255
266
|
end
|
256
267
|
|
@@ -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
|
@@ -6,16 +6,11 @@
|
|
6
6
|
#
|
7
7
|
# frozen_string_literal: true
|
8
8
|
|
9
|
-
require "digest/md5"
|
10
|
-
require "forwardable"
|
11
9
|
require "graphql"
|
12
10
|
require "elastic_graph/constants"
|
13
11
|
require "elastic_graph/errors"
|
14
|
-
require "elastic_graph/graphql/monkey_patches/schema_field"
|
15
|
-
require "elastic_graph/graphql/monkey_patches/schema_object"
|
16
12
|
require "elastic_graph/graphql/schema/field"
|
17
13
|
require "elastic_graph/graphql/schema/type"
|
18
|
-
require "elastic_graph/support/hash_util"
|
19
14
|
|
20
15
|
module ElasticGraph
|
21
16
|
# Wraps a GraphQL::Schema object in order to provide higher-level, more convenient APIs
|
@@ -29,19 +24,27 @@ module ElasticGraph
|
|
29
24
|
scalar_types.to_set.union(introspection_types)
|
30
25
|
)
|
31
26
|
|
32
|
-
attr_reader :element_names, :config, :graphql_schema, :runtime_metadata
|
27
|
+
attr_reader :element_names, :config, :logger, :graphql_schema, :runtime_metadata
|
33
28
|
|
34
29
|
def initialize(
|
35
30
|
graphql_schema_string:,
|
36
31
|
config:,
|
32
|
+
logger:,
|
37
33
|
runtime_metadata:,
|
34
|
+
datastore_search_router:,
|
38
35
|
index_definitions_by_graphql_type:,
|
39
36
|
graphql_gem_plugins:,
|
40
|
-
|
37
|
+
graphql_adapter:
|
41
38
|
)
|
42
39
|
@element_names = runtime_metadata.schema_element_names
|
43
40
|
@config = config
|
41
|
+
@logger = logger
|
44
42
|
@runtime_metadata = runtime_metadata
|
43
|
+
@datastore_search_router = datastore_search_router
|
44
|
+
|
45
|
+
resolvers_needing_lookahead = runtime_metadata.graphql_resolvers_by_name.filter_map do |name, resolver|
|
46
|
+
name if resolver.needs_lookahead
|
47
|
+
end.to_set
|
45
48
|
|
46
49
|
@types_by_graphql_type = Hash.new do |hash, key|
|
47
50
|
hash[key] = Type.new(
|
@@ -49,25 +52,55 @@ module ElasticGraph
|
|
49
52
|
key,
|
50
53
|
index_definitions_by_graphql_type[key.graphql_name] || [],
|
51
54
|
runtime_metadata.object_types_by_name[key.graphql_name],
|
52
|
-
runtime_metadata.enum_types_by_name[key.graphql_name]
|
55
|
+
runtime_metadata.enum_types_by_name[key.graphql_name],
|
56
|
+
resolvers_needing_lookahead
|
53
57
|
)
|
54
58
|
end
|
55
59
|
|
56
|
-
@build_resolver = build_resolver
|
57
|
-
|
58
60
|
# Note: as part of loading the schema, the GraphQL gem may use the resolver (such
|
59
61
|
# when a directive has a custom scalar) so we must wait to instantiate the schema
|
60
62
|
# as late as possible here. If we do this before initializing some of the instance
|
61
63
|
# variables above we'll get `NoMethodError` on `nil`.
|
62
64
|
@graphql_schema = ::GraphQL::Schema.from_definition(
|
63
65
|
graphql_schema_string,
|
64
|
-
|
66
|
+
base_types: {object: build_base_object_class},
|
67
|
+
default_resolve: graphql_adapter,
|
65
68
|
using: graphql_gem_plugins
|
66
69
|
)
|
67
70
|
|
68
71
|
# Pre-load all defined types so that all field extras can get configured as part
|
69
72
|
# of loading the schema, before we execute the first query.
|
70
73
|
@types_by_name = build_types_by_name
|
74
|
+
@graphql_schema.visibility.preload
|
75
|
+
|
76
|
+
log_hidden_types
|
77
|
+
end
|
78
|
+
|
79
|
+
def new_graphql_query(
|
80
|
+
query_string,
|
81
|
+
operation_name: nil,
|
82
|
+
variables: {},
|
83
|
+
context: {},
|
84
|
+
document: nil,
|
85
|
+
validate: true
|
86
|
+
)
|
87
|
+
::GraphQL::Query.new(
|
88
|
+
graphql_schema,
|
89
|
+
query_string,
|
90
|
+
variables: variables,
|
91
|
+
operation_name: operation_name,
|
92
|
+
document: document,
|
93
|
+
validate: validate,
|
94
|
+
context: context.merge({
|
95
|
+
datastore_search_router: @datastore_search_router,
|
96
|
+
elastic_graph_schema: self,
|
97
|
+
visibility_profile: VISIBILITY_PROFILE
|
98
|
+
})
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
def graphql_query_context
|
103
|
+
@graphql_query_context ||= new_graphql_query(nil).context
|
71
104
|
end
|
72
105
|
|
73
106
|
def type_from(graphql_type)
|
@@ -79,7 +112,7 @@ module ElasticGraph
|
|
79
112
|
# get type objects for wrapped types, but you need to get it from a field object of that
|
80
113
|
# type.
|
81
114
|
def type_named(type_name)
|
82
|
-
@types_by_name.fetch(type_name
|
115
|
+
@types_by_name.fetch(type_name)
|
83
116
|
rescue KeyError => e
|
84
117
|
msg = "No type named #{type_name} could be found"
|
85
118
|
msg += "; Possible alternatives: [#{e.corrections.join(", ").delete('"')}]." if e.corrections.any?
|
@@ -114,33 +147,44 @@ module ElasticGraph
|
|
114
147
|
end
|
115
148
|
|
116
149
|
def to_s
|
117
|
-
"#<#{self.class.name} 0x#{__id__.to_s(16)} indexed_document_types
|
150
|
+
"#<#{self.class.name} 0x#{__id__.to_s(16)} indexed_document_types=[#{indexed_document_types.map(&:name).sort.join(", ")}]>"
|
118
151
|
end
|
119
152
|
alias_method :inspect, :to_s
|
120
153
|
|
121
154
|
private
|
122
155
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
156
|
+
def build_base_object_class
|
157
|
+
schema = self
|
158
|
+
|
159
|
+
base_field_class = ::Class.new(::GraphQL::Schema::Field) do
|
160
|
+
define_method :visible? do |context|
|
161
|
+
return super(context) if context[:visibility_profile] == :boot
|
162
|
+
|
163
|
+
if schema.field_named(owner.graphql_name, graphql_name).hidden_from_queries?
|
164
|
+
return false
|
165
|
+
end
|
166
|
+
|
167
|
+
super(context)
|
168
|
+
end
|
132
169
|
end
|
133
170
|
|
134
|
-
|
135
|
-
|
136
|
-
|
171
|
+
::Class.new(::GraphQL::Schema::Object) do
|
172
|
+
field_class base_field_class
|
173
|
+
|
174
|
+
define_singleton_method :visible? do |context|
|
175
|
+
return super(context) if context[:visibility_profile] == :boot
|
176
|
+
|
177
|
+
if schema.type_named(graphql_name).hidden_from_queries?
|
178
|
+
return false
|
179
|
+
end
|
137
180
|
|
138
|
-
|
139
|
-
|
181
|
+
super(context)
|
182
|
+
end
|
183
|
+
end
|
140
184
|
end
|
141
185
|
|
142
186
|
def build_types_by_name
|
143
|
-
graphql_schema.types.transform_values do |graphql_type|
|
187
|
+
graphql_schema.types(visibility_profile: :boot).transform_values do |graphql_type|
|
144
188
|
@types_by_graphql_type[graphql_type]
|
145
189
|
end
|
146
190
|
end
|
@@ -156,6 +200,16 @@ module ElasticGraph
|
|
156
200
|
end
|
157
201
|
end.freeze
|
158
202
|
end
|
203
|
+
|
204
|
+
def log_hidden_types
|
205
|
+
hidden_types = @types_by_name.values.select(&:hidden_from_queries?)
|
206
|
+
return if hidden_types.empty?
|
207
|
+
|
208
|
+
logger.warn(
|
209
|
+
"#{hidden_types.size} GraphQL types were hidden from the schema due to their backing indices being " \
|
210
|
+
"inaccessible: #{hidden_types.map(&:name).sort.join(", ")}"
|
211
|
+
)
|
212
|
+
end
|
159
213
|
end
|
160
214
|
end
|
161
215
|
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
|
@@ -8,6 +8,7 @@
|
|
8
8
|
|
9
9
|
require "elastic_graph/datastore_core"
|
10
10
|
require "elastic_graph/graphql/config"
|
11
|
+
require "elastic_graph/constants"
|
11
12
|
require "elastic_graph/support/from_yaml_file"
|
12
13
|
|
13
14
|
module ElasticGraph
|
@@ -26,7 +27,7 @@ module ElasticGraph
|
|
26
27
|
def self.from_parsed_yaml(parsed_yaml, &datastore_client_customization_block)
|
27
28
|
new(
|
28
29
|
config: GraphQL::Config.from_parsed_yaml(parsed_yaml),
|
29
|
-
datastore_core: DatastoreCore.from_parsed_yaml(parsed_yaml,
|
30
|
+
datastore_core: DatastoreCore.from_parsed_yaml(parsed_yaml, &datastore_client_customization_block)
|
30
31
|
)
|
31
32
|
end
|
32
33
|
|
@@ -55,7 +56,7 @@ module ElasticGraph
|
|
55
56
|
|
56
57
|
# Apply any extension modules that have been configured.
|
57
58
|
@config.extension_modules.each { |mod| extend mod }
|
58
|
-
@runtime_metadata.graphql_extension_modules.each { |ext_mod| extend ext_mod.extension_class }
|
59
|
+
@runtime_metadata.graphql_extension_modules.each { |ext_mod| extend ext_mod.load_extension.extension_class }
|
59
60
|
end
|
60
61
|
|
61
62
|
# @private
|
@@ -78,8 +79,7 @@ module ElasticGraph
|
|
78
79
|
schema: schema,
|
79
80
|
monotonic_clock: monotonic_clock,
|
80
81
|
logger: logger,
|
81
|
-
slow_query_threshold_ms: @config.slow_query_latency_warning_threshold_in_ms
|
82
|
-
datastore_search_router: datastore_search_router
|
82
|
+
slow_query_threshold_ms: @config.slow_query_latency_warning_threshold_in_ms
|
83
83
|
)
|
84
84
|
end
|
85
85
|
end
|
@@ -88,26 +88,16 @@ module ElasticGraph
|
|
88
88
|
def schema
|
89
89
|
@schema ||= begin
|
90
90
|
require "elastic_graph/graphql/schema"
|
91
|
-
|
92
91
|
Schema.new(
|
93
92
|
graphql_schema_string: graphql_schema_string,
|
94
93
|
config: config,
|
94
|
+
logger: logger,
|
95
95
|
runtime_metadata: runtime_metadata,
|
96
|
+
datastore_search_router: datastore_search_router,
|
96
97
|
index_definitions_by_graphql_type: @datastore_core.index_definitions_by_graphql_type,
|
97
|
-
graphql_gem_plugins: graphql_gem_plugins
|
98
|
-
|
99
|
-
|
100
|
-
@schema = schema # assign this so that `#schema` returns the schema when `datastore_query_adapters` is called below
|
101
|
-
require "elastic_graph/graphql/resolvers/graphql_adapter"
|
102
|
-
Resolvers::GraphQLAdapter.new(
|
103
|
-
schema: schema,
|
104
|
-
datastore_query_builder: datastore_query_builder,
|
105
|
-
datastore_query_adapters: datastore_query_adapters,
|
106
|
-
runtime_metadata: runtime_metadata,
|
107
|
-
resolvers: graphql_resolvers
|
108
|
-
)
|
109
|
-
end
|
110
|
-
end
|
98
|
+
graphql_gem_plugins: graphql_gem_plugins,
|
99
|
+
graphql_adapter: graphql_adapter
|
100
|
+
)
|
111
101
|
end
|
112
102
|
end
|
113
103
|
|
@@ -128,7 +118,7 @@ module ElasticGraph
|
|
128
118
|
def datastore_query_builder
|
129
119
|
@datastore_query_builder ||= begin
|
130
120
|
require "elastic_graph/graphql/datastore_query"
|
131
|
-
DatastoreQuery::Builder.
|
121
|
+
DatastoreQuery::Builder.new(
|
132
122
|
filter_interpreter:,
|
133
123
|
filter_node_interpreter:,
|
134
124
|
runtime_metadata:,
|
@@ -143,35 +133,57 @@ module ElasticGraph
|
|
143
133
|
def graphql_gem_plugins
|
144
134
|
@graphql_gem_plugins ||= begin
|
145
135
|
require "graphql"
|
136
|
+
# As per https://graphql-ruby.org/language_tools/c_parser.html, loading the
|
137
|
+
# C parser causes the faster parser to be assigned as the `::GraphQL.default_parser`,
|
138
|
+
# providing greater efficiency.
|
139
|
+
#
|
140
|
+
# We load it here since this is where we load the GraphQL gem.
|
141
|
+
require "graphql/c_parser"
|
142
|
+
|
146
143
|
{
|
147
144
|
# We depend on this to avoid N+1 calls to the datastore.
|
148
145
|
::GraphQL::Dataloader => {},
|
149
|
-
#
|
150
|
-
|
151
|
-
|
146
|
+
# https://graphql-ruby.org/authorization/visibility.html
|
147
|
+
::GraphQL::Schema::Visibility => {
|
148
|
+
# The GraphQL gem internally cache the visibility per profile. Ideally, we'd have only a single profile,
|
149
|
+
# but that makes for a chicken-and-egg problem: our visibility logic depends on the schema being fully
|
150
|
+
# loaded, but the `visibility?` methods are called while loading the schema. To deal with that, we're
|
151
|
+
# using tw profiles:
|
152
|
+
#
|
153
|
+
# - `boot` is used while loading, and skips our normal visibility logic.
|
154
|
+
# - `main` is used after that and uses our normal visibility logic.
|
155
|
+
profiles: {:boot => {}, VISIBILITY_PROFILE => {}} # : ::Hash[::Symbol, ::Hash[::Symbol, untyped]]
|
156
|
+
}
|
152
157
|
}
|
153
158
|
end
|
154
159
|
end
|
155
160
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
)
|
167
|
-
|
168
|
-
list_records = Resolvers::ListRecords.new
|
161
|
+
def graphql_adapter
|
162
|
+
@graphql_adapter ||= begin
|
163
|
+
require "elastic_graph/graphql/resolvers/graphql_adapter_builder"
|
164
|
+
Resolvers::GraphQLAdapterBuilder.new(
|
165
|
+
named_resolvers: named_graphql_resolvers,
|
166
|
+
query_adapter: resolver_query_adapter,
|
167
|
+
runtime_metadata: runtime_metadata
|
168
|
+
).build
|
169
|
+
end
|
170
|
+
end
|
169
171
|
|
170
|
-
|
171
|
-
|
172
|
+
def resolver_query_adapter
|
173
|
+
@resolver_query_adapter ||= begin
|
174
|
+
require "elastic_graph/graphql/resolvers/query_adapter"
|
175
|
+
Resolvers::QueryAdapter.new(
|
176
|
+
datastore_query_builder: datastore_query_builder,
|
177
|
+
datastore_query_adapters: datastore_query_adapters
|
172
178
|
)
|
179
|
+
end
|
180
|
+
end
|
173
181
|
|
174
|
-
|
182
|
+
# @private
|
183
|
+
def named_graphql_resolvers
|
184
|
+
@named_graphql_resolvers ||= runtime_metadata.graphql_resolvers_by_name.transform_values do |resolver|
|
185
|
+
ext = resolver.load_resolver
|
186
|
+
(_ = ext.extension_class).new(elasticgraph_graphql: self, config: ext.config)
|
175
187
|
end
|
176
188
|
end
|
177
189
|
|
@@ -194,14 +206,13 @@ module ElasticGraph
|
|
194
206
|
filter_node_interpreter: filter_node_interpreter
|
195
207
|
),
|
196
208
|
GraphQL::QueryAdapter::Sort.new(order_by_arg_name: schema_element_names.order_by),
|
197
|
-
Aggregation::QueryAdapter.new(
|
198
|
-
schema: schema,
|
209
|
+
Aggregation::QueryAdapter::WithoutSchema.new(
|
199
210
|
config: config,
|
200
211
|
filter_args_translator: filter_args_translator,
|
201
212
|
runtime_metadata: runtime_metadata,
|
202
213
|
sub_aggregation_grouping_adapter: sub_aggregation_grouping_adapter
|
203
214
|
),
|
204
|
-
GraphQL::QueryAdapter::RequestedFields.new
|
215
|
+
GraphQL::QueryAdapter::RequestedFields::WithoutSchema.new
|
205
216
|
]
|
206
217
|
end
|
207
218
|
end
|
@@ -252,6 +263,8 @@ module ElasticGraph
|
|
252
263
|
# it's nice to load dependencies when needed.
|
253
264
|
def load_dependencies_eagerly
|
254
265
|
require "graphql"
|
266
|
+
require "graphql/c_parser"
|
267
|
+
|
255
268
|
::GraphQL.eager_load!
|
256
269
|
|
257
270
|
# run a simple GraphQL query to force load any dependencies needed to handle GraphQL queries
|
data/script/dump_time_zones
CHANGED
@@ -8,7 +8,7 @@ updated_code_filename = "#{__dir__}/../../tmp/updated_valid_time_zones.rb"
|
|
8
8
|
java_time_zones = `java --source 11 #{__dir__}/dump_time_zones.java`.split("\n")
|
9
9
|
|
10
10
|
::File.write(updated_code_filename, <<~EOS)
|
11
|
-
# Copyright 2024 Block, Inc.
|
11
|
+
# Copyright 2024 - 2025 Block, Inc.
|
12
12
|
#
|
13
13
|
# Use of this source code is governed by an MIT-style
|
14
14
|
# license that can be found in the LICENSE file or at
|