Class: ElasticGraph::GraphQL::Filtering::RangeQuery

Inherits:
Object
  • Object
show all
Defined in:
lib/elastic_graph/graphql/filtering/range_query.rb

Overview

Alternate ‘BooleanQuery` implementation for range queries. When we get a filter like this:

{some_field: {gt: 10, lt: 100}}

…we independently build a range query for each predicate. The datastore query structure would look like this:

{filter: [
  {range: {some_field: {gt: 10}}},
  {range: {some_field: {lt: 100}}}
]}

However, the ‘range` query allows these be combined, like so:

{filter: [
  {range: {some_field: {gt: 10, lt: 100}}}
]}

While we haven’t measured it, it’s likely to be more efficient (certainly not less efficient!), and it’s essential that we combine them when we are using ‘any_satisfy`. Consider this filter:

{some_field: {any_satisfy: {gt: 10, lt: 100}}}

This should match a document with ‘some_field: [5, 45, 200]` (since 45 is between 10 and 100), and not match a document with `some_field: [5, 200]` (since `some_field` has no value between 10 and 100). However, if we keep the range clauses separate, this document would match, because `some_field` has a value > 10 and a value < 100 (even though no single value satisfies both parts!). When we combine the clauses into a single `range` query then the filtering works like we expect.

Constant Summary collapse

SAME_TYPE_OPS =
{
  gt: [:gt, :gte],
  gte: [:gt, :gte],
  lt: [:lt, :lte],
  lte: [:lt, :lte]
}.freeze

Instance Method Summary collapse

Instance Method Details

#merge_into(bool_node) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/elastic_graph/graphql/filtering/range_query.rb', line 49

def merge_into(bool_node)
  existing_range_index = bool_node[:filter].find_index { |clause| clause.dig(:range, field_name) }

  if existing_range_index
    existing_range_hash = bool_node[:filter][existing_range_index].dig(:range, field_name)
    merged_range_hash = merge_operators(existing_range_hash)
    bool_node[:filter][existing_range_index] = {range: {field_name => merged_range_hash}}
  else
    bool_node[:filter] << {range: {field_name => {operator => value}}}
  end
end