class ActiveRecord::Relation::WhereClause
Attributes
Public Class Methods
empty()
click to toggle source
# File lib/where-or.rb, line 200 def self.empty new([], []) end
new(predicates, binds)
click to toggle source
# File lib/where-or.rb, line 116 def initialize(predicates, binds) @predicates = predicates @binds = binds end
Public Instance Methods
+(other)
click to toggle source
# File lib/where-or.rb, line 121 def +(other) ActiveRecord::Relation::WhereClause.new( predicates + other.predicates, binds + other.binds, ) end
-(other)
click to toggle source
monkey patching around the fact that the rails 4.2 implementation is an array of things, all 'and'd together but the rails 5 implemention that they backported replaces that array with ActiveRecord::Relation::WhereClause
that contains AND's and OR's … on testing, I discover it mostly works except when you attempt to use the preloader, which this hack here fixes.
# File lib/where-or.rb, line 132 def -(other) raise "where-or internal error: expect only empty array, not #{other.inspect}" unless other.empty? || (other.size == 1 && other.first.blank?) [self] end
==(other)
click to toggle source
# File lib/where-or.rb, line 190 def ==(other) other.is_a?(ActiveRecord::Relation::WhereClause) && predicates == other.predicates && binds == other.binds end
ast()
click to toggle source
# File lib/where-or.rb, line 186 def ast Arel::Nodes::And.new(predicates_with_wrapped_sql_literals) end
except(*columns)
click to toggle source
# File lib/where-or.rb, line 144 def except(*columns) ActiveRecord::Relation::WhereClause.new( predicates_except(columns), binds_except(columns), ) end
invert()
click to toggle source
# File lib/where-or.rb, line 196 def invert ActiveRecord::Relation::WhereClause.new(inverted_predicates, binds) end
merge(other)
click to toggle source
# File lib/where-or.rb, line 137 def merge(other) ActiveRecord::Relation::WhereClause.new( predicates_unreferenced_by(other) + other.predicates, non_conflicting_binds(other) + other.binds, ) end
or(other)
click to toggle source
# File lib/where-or.rb, line 151 def or(other) if empty? other elsif other.empty? self else ActiveRecord::Relation::WhereClause.new( [ast.or(other.ast)], binds + other.binds ) end end
to_h(table_name = nil)
click to toggle source
# File lib/where-or.rb, line 164 def to_h(table_name = nil) equalities = predicates.grep(Arel::Nodes::Equality) if table_name equalities = equalities.select do |node| node.left.relation.name == table_name end end binds = self.binds.map { |attr| [attr.name, attr.value] }.to_h equalities.map { |node| name = node.left.name [name, binds.fetch(name.to_s) { case node.right when Array then node.right.map(&:val) when Arel::Nodes::Casted, Arel::Nodes::Quoted node.right.val end }] }.to_h end
Protected Instance Methods
referenced_columns()
click to toggle source
# File lib/where-or.rb, line 206 def referenced_columns @referenced_columns ||= begin equality_nodes = predicates.select { |n| equality_node?(n) } Set.new(equality_nodes, &:left) end end
Private Instance Methods
binds_except(columns)
click to toggle source
# File lib/where-or.rb, line 260 def binds_except(columns) binds.reject do |attr| columns.include?(attr.name) end end
equality_node?(node)
click to toggle source
# File lib/where-or.rb, line 221 def equality_node?(node) node.respond_to?(:operator) && node.operator == :== end
invert_predicate(node)
click to toggle source
# File lib/where-or.rb, line 235 def invert_predicate(node) case node when NilClass raise ArgumentError, 'Invalid argument for .where.not(), got nil.' when Arel::Nodes::In Arel::Nodes::NotIn.new(node.left, node.right) when Arel::Nodes::Equality Arel::Nodes::NotEqual.new(node.left, node.right) when String Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node)) else Arel::Nodes::Not.new(node) end end
inverted_predicates()
click to toggle source
# File lib/where-or.rb, line 231 def inverted_predicates predicates.map { |node| invert_predicate(node) } end
non_conflicting_binds(other)
click to toggle source
# File lib/where-or.rb, line 225 def non_conflicting_binds(other) conflicts = referenced_columns & other.referenced_columns conflicts.map! { |node| node.name.to_s } binds.reject { |attr| conflicts.include?(attr.name) } end
non_empty_predicates()
click to toggle source
# File lib/where-or.rb, line 276 def non_empty_predicates predicates - [''] end
predicates_except(columns)
click to toggle source
# File lib/where-or.rb, line 250 def predicates_except(columns) predicates.reject do |node| case node when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThanOrEqual subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right) columns.include?(subrelation.name.to_s) end end end
predicates_unreferenced_by(other)
click to toggle source
# File lib/where-or.rb, line 215 def predicates_unreferenced_by(other) predicates.reject do |n| equality_node?(n) && other.referenced_columns.include?(n.left) end end
predicates_with_wrapped_sql_literals()
click to toggle source
# File lib/where-or.rb, line 266 def predicates_with_wrapped_sql_literals non_empty_predicates.map do |node| if Arel::Nodes::Equality === node node else wrap_sql_literal(node) end end end
wrap_sql_literal(node)
click to toggle source
# File lib/where-or.rb, line 280 def wrap_sql_literal(node) if ::String === node node = Arel.sql(node) end Arel::Nodes::Grouping.new(node) end