elasticgraph-graphql 0.19.0.0.rc1 → 0.19.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01af70cea7a26c2897ca64c179e0ed5a9a482a9229a46304b2e59b2f249148c3
4
- data.tar.gz: 9a6aca68a2663012e54bf022a7153ec4443b3bc59846c63b91e6084b07b61574
3
+ metadata.gz: 87e3b12d1297421b2631906b7c682d38f87d4111fc9929d56d2be55f6cc481fe
4
+ data.tar.gz: bb454a309d0869c7c0d446d5ca2882cda4d005e412966db327e3dab56c0916f8
5
5
  SHA512:
6
- metadata.gz: 5ead565225393723335e8dcc0dea15a6858dd005e5f96531ad60aa21b2cf0166760cb5c25e788b0dbb5d367c50ddb1335f9fd5129a2ee173df0d04c436e5ed15
7
- data.tar.gz: fc360a136de5620ac53375046dce9e93a90b19f4ea3eb2331f8ca2dbda2f2701b55156e04ac60f71ab4bf45c5eca4e45a2efcf2236cef25f78503ef1beca5cda
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1
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.rc1/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: []