Skip to content

Commit

Permalink
WIP on skipping contradicted queries
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyshields committed Oct 18, 2023
1 parent 512e165 commit 50a0f9b
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/mongoid/criteria.rb
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def none
#
# @return [ true | false ] If the criteria is a none.
def empty_and_chainable?
!!@none
!!@none || Queryable::Contradiction.contradicted?(self)
end

# Overriden to include _type in the fields.
Expand Down
49 changes: 49 additions & 0 deletions lib/mongoid/criteria/queryable/contradiciton.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

module Mongoid
class Criteria
module Queryable
# Checks whether the criteria contains a contradiction which
# would cause the query to return no results. This can result from:
# - Conflicting equals: { 'name' => 'Bob', 'name' => 'Joe' }
# - Empty $in: { '$in' => [] }
# - Not empty $nin: { '$not' => { '$nin' => [] } }
module Contradiction
extend self

def contradicted?(criteria)
traverse_selector(criteria.selector)
end

private

def traverse_selector(selector, negated = false)
# return true if selector.any? { |k, v| empty_condition?(k, v, '$in') }

# selector.all?
selector.each do |k, v|
return true if empty_condition?(k, v, '$in')

case k.to_s
when '$and'
Array(v).any? { |s| traverse_selector(s, negated) }
when '$or'
Array(v).all? { |s| traverse_selector(s, negated) }
when '$nor'
Array(v).all? { |s| traverse_selector(s, !negated) }
when '$not'
traverse_selector(selector, !negated)
end
end
end

def empty_condition?(key, value, operator)
!key.to_s.start_with?('$') &&
value.is_a?(Hash) &&
value.size == 1 &&
(value[operator] || value[operator.to_sym]) == []
end
end
end
end
end

0 comments on commit 50a0f9b

Please sign in to comment.