elasticgraph-graphql 0.19.0.0.rc2 → 0.19.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c907a36c44ef987d02202ff39ef9686c3bfc997ce80d9310da0e3364d89de5d0
4
- data.tar.gz: 1a2f992e201097a980b5fa4f16f9721f8f51d2888dc8d12f3267101765b3c7af
3
+ metadata.gz: 87e3b12d1297421b2631906b7c682d38f87d4111fc9929d56d2be55f6cc481fe
4
+ data.tar.gz: bb454a309d0869c7c0d446d5ca2882cda4d005e412966db327e3dab56c0916f8
5
5
  SHA512:
6
- metadata.gz: baba491d690547b7722d7b715af442b691c341abb0c29a25da6678e068d3199a7765829acd8121b756ee464685c7dba92b9beb0f2f34d2431b20e1e1783e347d
7
- data.tar.gz: 289be9c156185ff45b152a504fd6b72f61cba8982b61acf8373e18cf5bc10a70f9978db2c99040bdde0b4824d811b58b812290e3fc08b809940bf998b975022e
6
+ metadata.gz: 803c34dfff0d787e61987f5d1877ea93485180161d3f1fc730bf6989d52f17e929c7fe476b434d4d59d59acf86622c5f68e6b2ed2f050df4abcdc13257c33bb8
7
+ data.tar.gz: 505707f3dd8bab37cc388cc542c343d4a541f5354c8e192d131a3cff36096e2d1ad9578872a68b169806f476acf0bdfd46d4db5389bb8e1dce09a984745265df
@@ -13,7 +13,7 @@ ElasticGraphGemspecHelper.define_elasticgraph_gem(gemspec_file: __FILE__, catego
13
13
 
14
14
  spec.add_dependency "elasticgraph-datastore_core", eg_version
15
15
  spec.add_dependency "elasticgraph-schema_artifacts", eg_version
16
- spec.add_dependency "graphql", "~> 2.4.5"
16
+ spec.add_dependency "graphql", "~> 2.4.8"
17
17
 
18
18
  spec.add_development_dependency "elasticgraph-admin", eg_version
19
19
  spec.add_development_dependency "elasticgraph-elasticsearch", eg_version
@@ -154,7 +154,7 @@ module ElasticGraph
154
154
  # If there are no aggregations, there's nothing to unmerge--just return it as is.
155
155
  return response_from_merged_query unless (aggs = response_from_merged_query["aggregations"])
156
156
 
157
- prefix = @unique_prefix_by_query[original_query]
157
+ prefix = @unique_prefix_by_query[original_query] # : ::String
158
158
  agg_names = original_query.aggregations.keys.map { |name| "#{prefix}#{name}" }.to_set
159
159
 
160
160
  filtered_aggs = aggs
@@ -14,8 +14,13 @@ module ElasticGraph
14
14
  class DatastoreQuery
15
15
  # Responsible for building a search index expression for a specific query based on the filters.
16
16
  class IndexExpressionBuilder
17
- def initialize(schema_names:)
18
- @filter_value_set_extractor = Filtering::FilterValueSetExtractor.new(schema_names, Support::TimeSet::ALL, Support::TimeSet::EMPTY) do |operator, filter_value|
17
+ def initialize(filter_node_interpreter:, schema_names:)
18
+ @filter_value_set_extractor = Filtering::FilterValueSetExtractor.new(
19
+ filter_node_interpreter,
20
+ schema_names,
21
+ Support::TimeSet::ALL,
22
+ Support::TimeSet::EMPTY
23
+ ) do |operator, filter_value|
19
24
  case operator
20
25
  when :gt, :gte, :lt, :lte
21
26
  if date_string?(filter_value)
@@ -73,6 +78,8 @@ module ElasticGraph
73
78
 
74
79
  time_set = @filter_value_set_extractor.extract_filter_value_set(filter_hashes, [index_def.timestamp_field_path])
75
80
 
81
+ return IndexExpression.only(index_def.index_expression_for_search) if time_set.nil?
82
+
76
83
  if time_set.empty?
77
84
  return require_indices ?
78
85
  # Indices are required. Given the time set is empty, it's impossible for any documents to match our search.
@@ -13,21 +13,19 @@ module ElasticGraph
13
13
  class DatastoreQuery
14
14
  # Responsible for picking routing values for a specific query based on the filters.
15
15
  class RoutingPicker
16
- def initialize(schema_names:)
17
- # @type var all_values_set: _RoutingValueSet
16
+ def initialize(filter_node_interpreter:, schema_names:)
18
17
  all_values_set = RoutingValueSet::ALL
19
18
  empty_set = RoutingValueSet::EMPTY
20
19
 
21
- @filter_value_set_extractor = Filtering::FilterValueSetExtractor.new(schema_names, all_values_set, empty_set) do |operator, filter_value|
20
+ @filter_value_set_extractor = Filtering::FilterValueSetExtractor.new(
21
+ filter_node_interpreter,
22
+ schema_names,
23
+ all_values_set,
24
+ empty_set
25
+ ) do |operator, filter_value|
22
26
  if operator == :equal_to_any_of
23
27
  # This calls `.compact` to remove `nil` filter_value values
24
28
  RoutingValueSet.of(filter_value.compact)
25
- else # gt, lt, gte, lte, matches
26
- # With one of these inexact/inequality operators, we don't have a way to precisely represent
27
- # the set of values. Instead, we represent it with the special UnboundedWithExclusions
28
- # implementation since when these operators are used the set is unbounded (there's an infinite
29
- # number of values in the set) but it doesn't contain all values (it has some exclusions).
30
- RoutingValueSet::UnboundedWithExclusions
31
29
  end
32
30
  end
33
31
  end
@@ -55,13 +53,11 @@ module ElasticGraph
55
53
  # end
56
54
  # ```
57
55
  def extract_eligible_routing_values(filter_hashes, routing_field_paths)
58
- @filter_value_set_extractor.extract_filter_value_set(filter_hashes, routing_field_paths).to_return_value
56
+ @filter_value_set_extractor.extract_filter_value_set(filter_hashes, routing_field_paths)&.to_return_value
59
57
  end
60
58
  end
61
59
 
62
60
  class RoutingValueSet < Data.define(:type, :routing_values)
63
- # @dynamic ==
64
-
65
61
  def self.of(routing_values)
66
62
  new(:inclusive, routing_values.to_set)
67
63
  end
@@ -73,15 +69,7 @@ module ElasticGraph
73
69
  ALL = of_all_except([])
74
70
  EMPTY = of([])
75
71
 
76
- def intersection(other_set)
77
- # Here we return `self` to preserve the commutative property of `intersection`. Returning `self`
78
- # here matches the behavior of `UnboundedWithExclusions.intersection`. See the comment there for
79
- # rationale.
80
- return self if other_set == UnboundedWithExclusions
81
-
82
- # @type var other: RoutingValueSet
83
- other = _ = other_set
84
-
72
+ def intersection(other)
85
73
  if inclusive? && other.inclusive?
86
74
  # Since both sets are inclusive, we can just delegate to `Set#intersection` here.
87
75
  RoutingValueSet.of(routing_values.intersection(other.routing_values))
@@ -111,15 +99,7 @@ module ElasticGraph
111
99
  end
112
100
  end
113
101
 
114
- def union(other_set)
115
- # Here we return `other` to preserve the commutative property of `union`. Returning `other`
116
- # here matches the behavior of `UnboundedWithExclusions.union`. See the comment there for
117
- # rationale.
118
- return other_set if other_set == UnboundedWithExclusions
119
-
120
- # @type var other: RoutingValueSet
121
- other = _ = other_set
122
-
102
+ def union(other)
123
103
  if inclusive? && other.inclusive?
124
104
  # Since both sets are inclusive, we can just delegate to `Set#union` here.
125
105
  RoutingValueSet.of(routing_values.union(other.routing_values))
@@ -180,52 +160,6 @@ module ElasticGraph
180
160
  def get_included_and_excluded_values(other)
181
161
  inclusive? ? [routing_values, other.routing_values] : [other.routing_values, routing_values]
182
162
  end
183
-
184
- # This `RoutingValueSet` implementation is used for otherwise unrepresentable cases. We use it when
185
- # a filter on one of the `routing_field_paths` uses an inequality like:
186
- #
187
- # {routing_field: {gt: "abc"}}
188
- #
189
- # In a case like that, the set is unbounded (there's an infinite number of values that are greater
190
- # than `"abc"`...), but it's not `RoutingValueSet::ALL`--since it's based on an inequality, there are
191
- # _some_ values that are excluded from the set. But we can't use `RoutingValueSet.of_all_except(...)`
192
- # because the set of exclusions is also unbounded!
193
- #
194
- # When our filter value extraction results in this set, we must search all shards of the index and
195
- # cannot pass any `routing` value to the datastore at all.
196
- module UnboundedWithExclusions
197
- # @dynamic self.==
198
-
199
- def self.intersection(other)
200
- # Technically, the "true" intersection would be `other - values_of(self)` but as we don't have
201
- # any known values from this unbounded set, we just return `other`. It's OK to include extra values
202
- # in the set (we'll search additional shards) but not OK to fail to include necessary values in
203
- # the set (we'd avoid searching a shard that may have matching documents) so we err on the side of
204
- # including more values.
205
- other
206
- end
207
-
208
- def self.union(other)
209
- # Since our set here is unbounded, the resulting union is also unbounded. This errs on the side
210
- # of safety since this set's `to_return_value` returns `nil` to cause the datastore to search
211
- # all shards.
212
- self
213
- end
214
-
215
- def self.negate
216
- # This here is the only difference in behavior of this set implementation vs `RoutingValueSet::ALL`.
217
- # Where as `ALL.negate` returns an empty set, we treat `negate` as a no-op. We do that because the
218
- # negation of an inexact unbounded set is still an inexact unbounded set. While it flips which values
219
- # are in or out of the set, this object is still the representation in our datamodel for that case.
220
- self
221
- end
222
-
223
- def self.to_return_value
224
- # Here we return `nil` to make sure that the datastore searches all shards, since we don't have
225
- # any information we can use to safely limit what shards it searches.
226
- nil
227
- end
228
- end
229
163
  end
230
164
 
231
165
  # `Query::RoutingPicker` exists only for use by `Query` and is effectively private.
@@ -344,17 +344,23 @@ module ElasticGraph
344
344
 
345
345
  # Encapsulates dependencies of `Query`, giving us something we can expose off of `application`
346
346
  # to build queries when desired.
347
- class Builder < Support::MemoizableData.define(:runtime_metadata, :logger, :query_defaults)
348
- def self.with(runtime_metadata:, logger:, **query_defaults)
349
- new(runtime_metadata: runtime_metadata, logger: logger, query_defaults: query_defaults)
347
+ class Builder < Support::MemoizableData.define(:runtime_metadata, :logger, :filter_node_interpreter, :query_defaults)
348
+ def self.with(runtime_metadata:, logger:, filter_node_interpreter:, **query_defaults)
349
+ new(runtime_metadata:, logger:, filter_node_interpreter:, query_defaults:)
350
350
  end
351
351
 
352
352
  def routing_picker
353
- @routing_picker ||= RoutingPicker.new(schema_names: runtime_metadata.schema_element_names)
353
+ @routing_picker ||= RoutingPicker.new(
354
+ filter_node_interpreter: filter_node_interpreter,
355
+ schema_names: runtime_metadata.schema_element_names
356
+ )
354
357
  end
355
358
 
356
359
  def index_expression_builder
357
- @index_expression_builder ||= IndexExpressionBuilder.new(schema_names: runtime_metadata.schema_element_names)
360
+ @index_expression_builder ||= IndexExpressionBuilder.new(
361
+ filter_node_interpreter: filter_node_interpreter,
362
+ schema_names: runtime_metadata.schema_element_names
363
+ )
358
364
  end
359
365
 
360
366
  def new_query(**options)
@@ -26,7 +26,7 @@ module ElasticGraph
26
26
  # vs GraphQL.
27
27
  def translate_filter_args(field:, args:)
28
28
  return nil unless (filter_hash = args[filter_arg_name])
29
- filter_type = field.schema.type_from(field.graphql_field.arguments[filter_arg_name].type)
29
+ filter_type = field.schema.type_from(field.graphql_field.arguments.fetch(filter_arg_name).type)
30
30
  convert(filter_type, filter_hash)
31
31
  end
32
32
 
@@ -137,8 +137,6 @@ module ElasticGraph
137
137
  # this because we do not generate `any_satisfy` filters on `object` list fields (instead,
138
138
  # they get generated on their leaf fields).
139
139
  def process_list_any_filter_expression(bool_node, filter, field_path)
140
- return if filter.nil? || filter == {}
141
-
142
140
  if filters_on_sub_fields?(filter)
143
141
  process_any_satisfy_filter_expression_on_nested_object_list(bool_node, filter, field_path)
144
142
  else
@@ -195,8 +193,6 @@ module ElasticGraph
195
193
  # * `filter: {anyOf: [{field: null}]}` -> return all results
196
194
  # * `filter: {anyOf: [{field: null}, {field: ...}]}` -> return all results
197
195
  def process_any_of_expression(bool_node, expressions, field_path)
198
- return if expressions.nil? || expressions == {}
199
-
200
196
  if expressions.empty?
201
197
  # When our `expressions` array is empty, we want to match no documents. However, that's
202
198
  # not the behavior the datastore will give us if we have an empty array in the query under
@@ -218,8 +214,6 @@ module ElasticGraph
218
214
  end
219
215
 
220
216
  def process_all_of_expression(bool_node, expressions, field_path)
221
- return if expressions.nil? || expressions == {}
222
-
223
217
  # `all_of` represents an AND. AND is the default way that `process_filter_hash` combines
224
218
  # filters so we just have to call it for each sub-expression.
225
219
  expressions.each do |sub_expression|
@@ -228,8 +222,6 @@ module ElasticGraph
228
222
  end
229
223
 
230
224
  def process_operator_expression(bool_node, operator, expression, field_path)
231
- return if expression.nil? || expression == {}
232
-
233
225
  # `operator` is a filtering operator, and `expression` is the value the filtering
234
226
  # operator should be applied to. The `op_applicator` lambda, when called, will
235
227
  # return a Clause instance (defined in this module).
@@ -317,8 +309,6 @@ module ElasticGraph
317
309
  end
318
310
 
319
311
  def process_list_count_expression(bool_node, expression, field_path)
320
- return if expression.nil? || expression == {}
321
-
322
312
  # Normally, we don't have to do anything special for list count expressions.
323
313
  # That's the case, for example, for an expression like:
324
314
  #
@@ -25,33 +25,30 @@ module ElasticGraph
25
25
  end
26
26
 
27
27
  def identify_node_type(field_or_op, sub_expression)
28
- identify_by_field_or_op(field_or_op) || identify_by_sub_expr(sub_expression) || :unknown
29
- end
30
-
31
- def filter_operators
32
- @filter_operators ||= build_filter_operators(runtime_metadata)
33
- end
28
+ # `:not` must go before `:empty`, because `not: empty_filter` must be inverted from just `empty_filter`.
29
+ return :not if field_or_op == schema_names.not
34
30
 
35
- private
31
+ # The `:empty` check can go before all other checks; besides `not`, none of the other operators require special
32
+ # handling when the filter is empty, and we want to detect this as early as possible.
33
+ # Note: `any_of: [empty_filter]` does have special handling, but `any_of: empty_filter` does not.
34
+ return :empty if sub_expression.nil? || sub_expression == {}
36
35
 
37
- def identify_by_field_or_op(field_or_op)
38
- return :not if field_or_op == schema_names.not
39
36
  return :list_any_filter if field_or_op == schema_names.any_satisfy
40
37
  return :all_of if field_or_op == schema_names.all_of
41
38
  return :any_of if field_or_op == schema_names.any_of
42
39
  return :operator if filter_operators.key?(field_or_op)
43
40
  return :list_count if field_or_op == LIST_COUNTS_FIELD
41
+ return :sub_field if sub_expression.is_a?(::Hash)
44
42
 
45
- nil
43
+ :unknown
46
44
  end
47
45
 
48
- def identify_by_sub_expr(sub_expression)
49
- return :empty if sub_expression.nil? || sub_expression == {}
50
- return :sub_field if sub_expression.is_a?(::Hash)
51
-
52
- nil
46
+ def filter_operators
47
+ @filter_operators ||= build_filter_operators(runtime_metadata)
53
48
  end
54
49
 
50
+ private
51
+
55
52
  def build_filter_operators(runtime_metadata)
56
53
  filter_by_time_of_day_script_id = runtime_metadata
57
54
  .static_script_ids_by_scoped_name
@@ -12,7 +12,8 @@ module ElasticGraph
12
12
  # Responsible for extracting a set of values from query filters, based on a using a custom
13
13
  # set type that is able to efficiently model the "all values" case.
14
14
  class FilterValueSetExtractor
15
- def initialize(schema_names, all_values_set, empty_set, &build_set_for_filter)
15
+ def initialize(filter_node_interpreter, schema_names, all_values_set, empty_set, &build_set_for_filter)
16
+ @filter_node_interpreter = filter_node_interpreter
16
17
  @schema_names = schema_names
17
18
  @all_values_set = all_values_set
18
19
  @empty_set = empty_set
@@ -41,9 +42,12 @@ module ElasticGraph
41
42
  # routing values causes no adverse behavior (although it may introduce an inefficiency)
42
43
  # but if we fail to route to a shard that contains a matching document, the search results
43
44
  # will be incorrect.
44
- map_reduce_sets(target_field_paths, :union, negate: false) do |target_field_path|
45
+ value_set = map_reduce_sets(target_field_paths, :union, negate: false) do |target_field_path|
45
46
  filter_value_set_for_target_field_path(target_field_path, filter_hashes)
46
47
  end
48
+
49
+ return nil if (_ = value_set) == UnboundedSetWithExclusions
50
+ _ = value_set
47
51
  end
48
52
 
49
53
  private
@@ -83,24 +87,32 @@ module ElasticGraph
83
87
  # the key could identify either a field we are filtering on or a filtering operator to apply
84
88
  # to a particular field.
85
89
  def filter_value_set_for_filter_hash_entry(field_or_op, filter_value, target_field_path_parts, traversed_field_path_parts, negate:)
86
- if filter_value.nil?
87
- # Any filter with a `nil` value is effectively treated as `true` by our filtering logic, so we need
90
+ node_type = @filter_node_interpreter.identify_node_type(field_or_op, filter_value)
91
+ case node_type
92
+ when :empty
93
+ # Any empty filter is effectively treated as `true` by our filtering logic, so we need
88
94
  # to return our `@all_values_set` to indicate this filter matches all documents.
89
95
  @all_values_set
90
- elsif field_or_op == @schema_names.not
91
- filter_value_set_for_filter_hash(filter_value, target_field_path_parts, traversed_field_path_parts, negate: !negate)
92
- elsif filter_value.is_a?(::Hash)
93
- # the only time `value` is a hash is when `field_or_op` is a field name.
94
- # In that case, `value` is a hash of filters that apply to that field.
96
+ when :not
97
+ filter_value_set_for_filter_hash(filter_value || {}, target_field_path_parts, traversed_field_path_parts, negate: !negate)
98
+ when :sub_field
95
99
  filter_value_set_for_filter_hash(filter_value, target_field_path_parts, traversed_field_path_parts + [field_or_op], negate: negate)
96
- elsif field_or_op == @schema_names.any_of
100
+ when :any_of
97
101
  filter_value_set_for_any_of(filter_value, target_field_path_parts, traversed_field_path_parts, negate: negate)
98
- elsif target_field_path_parts == traversed_field_path_parts
102
+ when :operator
103
+ # Check to make sure the operator applies to the target field. If not, we have no information
104
+ # in this clause. The set is unbounded, and may have exclusions.
105
+ return UnboundedSetWithExclusions unless target_field_path_parts == traversed_field_path_parts
106
+
99
107
  set = filter_value_set_for_field_filter(field_or_op, filter_value)
100
108
  negate ? set.negate : set
109
+ when :all_of, :list_any_filter, :list_count, :unknown
110
+ # We have no information in this clause. The set is unbounded, and may have exclusions.
111
+ UnboundedSetWithExclusions
101
112
  else
102
- # Otherwise, we have no information in this clause to limit our filter value set.
103
- @all_values_set
113
+ # :nocov: -- not possible to cover without mocking `@filter_node_interpreter` to return a node type outside the allowed values.
114
+ raise "`FilterValueSetExtractor` must be updated to handle `:#{node_type}` nodes."
115
+ # :nocov:
104
116
  end
105
117
  end
106
118
 
@@ -125,7 +137,7 @@ module ElasticGraph
125
137
  # Determines the set of filter values for a single filter on a single field.
126
138
  def filter_value_set_for_field_filter(filter_op, filter_value)
127
139
  operator_name = @schema_names.canonical_name_for(filter_op)
128
- @build_set_for_filter.call(operator_name, filter_value) || @all_values_set
140
+ @build_set_for_filter.call(operator_name, filter_value) || UnboundedSetWithExclusions
129
141
  end
130
142
 
131
143
  # Maps over the provided `collection` by applying the given `map_transform`
@@ -144,10 +156,49 @@ module ElasticGraph
144
156
  # of each set is the difference between @all_values_set and the given set)--and vice versa.
145
157
  reduction = REDUCTION_INVERSIONS.fetch(reduction) if negate
146
158
 
147
- collection.map(&map_transform).reduce(reduction)
159
+ collection.map(&map_transform).reduce do |s1, s2|
160
+ receiver, argument = ((_ = s2) == UnboundedSetWithExclusions) ? [s2, s1] : [s1, s2]
161
+ (reduction == :union) ? receiver.union(argument) : receiver.intersection(argument)
162
+ end
148
163
  end
149
164
 
150
165
  REDUCTION_INVERSIONS = {union: :intersection, intersection: :union}
166
+
167
+ # This minimal set implementation is used for otherwise unrepresentable cases. We use it when
168
+ # a filter on a `target_field_path` uses an inequality like:
169
+ #
170
+ # {field: {gt: "abc"}}
171
+ #
172
+ # In a case like that, the set is unbounded (there's an infinite number of values that are greater
173
+ # than `"abc"`...), but it's not `@all_values_set`--since it's based on an inequality, there are
174
+ # _some_ values that are excluded from the set. We also can't represent this case with an
175
+ # `all_values_except(...)` set implementation because the set of exclusions is also unbounded!
176
+ #
177
+ # When our filter value extraction results in this set, we cannot limit what shards or indices we must hit based
178
+ # on the filters.
179
+ module UnboundedSetWithExclusions
180
+ def self.intersection(other)
181
+ # Technically, the accurate intersection would be `other - values_of(self)` but as we don't have
182
+ # any known values from this unbounded set, we just return `other`. It's OK to include extra values
183
+ # in the set (we'll search additional shards or indices) but not OK to fail to include necessary values
184
+ # in the set (we'd avoid searching a shard that may have matching documents) so we err on the side of
185
+ # including more values.
186
+ other
187
+ end
188
+
189
+ def self.union(other)
190
+ # Since our set here is unbounded, the resulting union is also unbounded.
191
+ self
192
+ end
193
+
194
+ def self.negate
195
+ # The negation of an `UnboundedSetWithExclusions` is still an `UnboundedSetWithExclusions`. While it would flip
196
+ # which values are in or out of the set, this object is still the representation in our data model for that case.
197
+ self
198
+ end
199
+ end
200
+
201
+ private_constant :UnboundedSetWithExclusions
151
202
  end
152
203
  end
153
204
  end
@@ -197,7 +197,7 @@ module ElasticGraph
197
197
  end
198
198
 
199
199
  def content_type
200
- @content_type ||= normalized_headers["CONTENT-TYPE"]
200
+ normalized_headers["CONTENT-TYPE"]
201
201
  end
202
202
 
203
203
  def self.normalize_header_name(header)
@@ -96,12 +96,18 @@ module ElasticGraph
96
96
  # on `filter_value_set_extractor` to determine it, since it understands the semantics
97
97
  # of `any_of`, `not`, etc.
98
98
  def can_match_nil_values_at?(path, filter)
99
- filter_value_set_extractor.extract_filter_value_set([filter], [path]).includes_nil?
99
+ value_set = filter_value_set_extractor.extract_filter_value_set([filter], [path])
100
+ (_ = value_set).nil? || value_set.includes_nil?
100
101
  end
101
102
 
102
103
  def filter_value_set_extractor
103
104
  @filter_value_set_extractor ||=
104
- Filtering::FilterValueSetExtractor.new(schema_element_names, IncludesNilSet, ExcludesNilSet) do |operator, filter_value|
105
+ Filtering::FilterValueSetExtractor.new(
106
+ filter_node_interpreter,
107
+ schema_element_names,
108
+ IncludesNilSet,
109
+ ExcludesNilSet
110
+ ) do |operator, filter_value|
105
111
  if operator == :equal_to_any_of && filter_value.include?(nil)
106
112
  IncludesNilSet
107
113
  else
@@ -25,7 +25,7 @@ module ElasticGraph
25
25
  def fetch(queries)
26
26
  responses_by_query = @datastore_router.msearch(queries, query_tracker: @query_tracker)
27
27
  @query_tracker.record_datastore_queries_for_single_request(queries)
28
- queries.map { |q| responses_by_query[q] }
28
+ queries.map { |q| responses_by_query.fetch(q) }
29
29
  end
30
30
 
31
31
  def self.execute_many(queries, for_context:)
@@ -129,9 +129,10 @@ module ElasticGraph
129
129
  @datastore_query_builder ||= begin
130
130
  require "elastic_graph/graphql/datastore_query"
131
131
  DatastoreQuery::Builder.with(
132
- filter_interpreter: filter_interpreter,
133
- runtime_metadata: runtime_metadata,
134
- logger: logger,
132
+ filter_interpreter:,
133
+ filter_node_interpreter:,
134
+ runtime_metadata:,
135
+ logger:,
135
136
  default_page_size: @config.default_page_size,
136
137
  max_page_size: @config.max_page_size
137
138
  )
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticgraph-graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.0.0.rc2
4
+ version: 0.19.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Myron Marston
8
8
  - Ben VandenBos
9
9
  - Block Engineering
10
- autorequire:
10
+ autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2024-12-03 00:00:00.000000000 Z
13
+ date: 2024-12-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop-factory_bot
@@ -74,14 +74,14 @@ dependencies:
74
74
  requirements:
75
75
  - - "~>"
76
76
  - !ruby/object:Gem::Version
77
- version: '1.8'
77
+ version: 1.9.0
78
78
  type: :development
79
79
  prerelease: false
80
80
  version_requirements: !ruby/object:Gem::Requirement
81
81
  requirements:
82
82
  - - "~>"
83
83
  - !ruby/object:Gem::Version
84
- version: '1.8'
84
+ version: 1.9.0
85
85
  - !ruby/object:Gem::Dependency
86
86
  name: coderay
87
87
  requirement: !ruby/object:Gem::Requirement
@@ -268,113 +268,113 @@ dependencies:
268
268
  requirements:
269
269
  - - '='
270
270
  - !ruby/object:Gem::Version
271
- version: 0.19.0.0.rc2
271
+ version: 0.19.0.0
272
272
  type: :runtime
273
273
  prerelease: false
274
274
  version_requirements: !ruby/object:Gem::Requirement
275
275
  requirements:
276
276
  - - '='
277
277
  - !ruby/object:Gem::Version
278
- version: 0.19.0.0.rc2
278
+ version: 0.19.0.0
279
279
  - !ruby/object:Gem::Dependency
280
280
  name: elasticgraph-schema_artifacts
281
281
  requirement: !ruby/object:Gem::Requirement
282
282
  requirements:
283
283
  - - '='
284
284
  - !ruby/object:Gem::Version
285
- version: 0.19.0.0.rc2
285
+ version: 0.19.0.0
286
286
  type: :runtime
287
287
  prerelease: false
288
288
  version_requirements: !ruby/object:Gem::Requirement
289
289
  requirements:
290
290
  - - '='
291
291
  - !ruby/object:Gem::Version
292
- version: 0.19.0.0.rc2
292
+ version: 0.19.0.0
293
293
  - !ruby/object:Gem::Dependency
294
294
  name: graphql
295
295
  requirement: !ruby/object:Gem::Requirement
296
296
  requirements:
297
297
  - - "~>"
298
298
  - !ruby/object:Gem::Version
299
- version: 2.4.5
299
+ version: 2.4.8
300
300
  type: :runtime
301
301
  prerelease: false
302
302
  version_requirements: !ruby/object:Gem::Requirement
303
303
  requirements:
304
304
  - - "~>"
305
305
  - !ruby/object:Gem::Version
306
- version: 2.4.5
306
+ version: 2.4.8
307
307
  - !ruby/object:Gem::Dependency
308
308
  name: elasticgraph-admin
309
309
  requirement: !ruby/object:Gem::Requirement
310
310
  requirements:
311
311
  - - '='
312
312
  - !ruby/object:Gem::Version
313
- version: 0.19.0.0.rc2
313
+ version: 0.19.0.0
314
314
  type: :development
315
315
  prerelease: false
316
316
  version_requirements: !ruby/object:Gem::Requirement
317
317
  requirements:
318
318
  - - '='
319
319
  - !ruby/object:Gem::Version
320
- version: 0.19.0.0.rc2
320
+ version: 0.19.0.0
321
321
  - !ruby/object:Gem::Dependency
322
322
  name: elasticgraph-elasticsearch
323
323
  requirement: !ruby/object:Gem::Requirement
324
324
  requirements:
325
325
  - - '='
326
326
  - !ruby/object:Gem::Version
327
- version: 0.19.0.0.rc2
327
+ version: 0.19.0.0
328
328
  type: :development
329
329
  prerelease: false
330
330
  version_requirements: !ruby/object:Gem::Requirement
331
331
  requirements:
332
332
  - - '='
333
333
  - !ruby/object:Gem::Version
334
- version: 0.19.0.0.rc2
334
+ version: 0.19.0.0
335
335
  - !ruby/object:Gem::Dependency
336
336
  name: elasticgraph-opensearch
337
337
  requirement: !ruby/object:Gem::Requirement
338
338
  requirements:
339
339
  - - '='
340
340
  - !ruby/object:Gem::Version
341
- version: 0.19.0.0.rc2
341
+ version: 0.19.0.0
342
342
  type: :development
343
343
  prerelease: false
344
344
  version_requirements: !ruby/object:Gem::Requirement
345
345
  requirements:
346
346
  - - '='
347
347
  - !ruby/object:Gem::Version
348
- version: 0.19.0.0.rc2
348
+ version: 0.19.0.0
349
349
  - !ruby/object:Gem::Dependency
350
350
  name: elasticgraph-indexer
351
351
  requirement: !ruby/object:Gem::Requirement
352
352
  requirements:
353
353
  - - '='
354
354
  - !ruby/object:Gem::Version
355
- version: 0.19.0.0.rc2
355
+ version: 0.19.0.0
356
356
  type: :development
357
357
  prerelease: false
358
358
  version_requirements: !ruby/object:Gem::Requirement
359
359
  requirements:
360
360
  - - '='
361
361
  - !ruby/object:Gem::Version
362
- version: 0.19.0.0.rc2
362
+ version: 0.19.0.0
363
363
  - !ruby/object:Gem::Dependency
364
364
  name: elasticgraph-schema_definition
365
365
  requirement: !ruby/object:Gem::Requirement
366
366
  requirements:
367
367
  - - '='
368
368
  - !ruby/object:Gem::Version
369
- version: 0.19.0.0.rc2
369
+ version: 0.19.0.0
370
370
  type: :development
371
371
  prerelease: false
372
372
  version_requirements: !ruby/object:Gem::Requirement
373
373
  requirements:
374
374
  - - '='
375
375
  - !ruby/object:Gem::Version
376
- version: 0.19.0.0.rc2
377
- description:
376
+ version: 0.19.0.0
377
+ description:
378
378
  email:
379
379
  - myron@squareup.com
380
380
  executables: []
@@ -466,12 +466,12 @@ licenses:
466
466
  - MIT
467
467
  metadata:
468
468
  bug_tracker_uri: https://github.com/block/elasticgraph/issues
469
- changelog_uri: https://github.com/block/elasticgraph/releases/tag/v0.19.0.0.rc2
469
+ changelog_uri: https://github.com/block/elasticgraph/releases/tag/v0.19.0.0
470
470
  documentation_uri: https://block.github.io/elasticgraph/docs/main/
471
471
  homepage_uri: https://block.github.io/elasticgraph/
472
- source_code_uri: https://github.com/block/elasticgraph/tree/v0.19.0.0.rc2/elasticgraph-graphql
472
+ source_code_uri: https://github.com/block/elasticgraph/tree/v0.19.0.0/elasticgraph-graphql
473
473
  gem_category: core
474
- post_install_message:
474
+ post_install_message:
475
475
  rdoc_options: []
476
476
  require_paths:
477
477
  - lib
@@ -486,8 +486,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
486
486
  - !ruby/object:Gem::Version
487
487
  version: '0'
488
488
  requirements: []
489
- rubygems_version: 3.5.9
490
- signing_key:
489
+ rubygems_version: 3.5.22
490
+ signing_key:
491
491
  specification_version: 4
492
492
  summary: The ElasticGraph GraphQL query engine.
493
493
  test_files: []