aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorErnie Miller <ernie@erniemiller.org>2012-08-18 22:33:25 -0400
committerErnie Miller <ernie@erniemiller.org>2012-08-18 22:33:25 -0400
commit6e638bba594b6164190d2a6fb96ffa07a20b11f3 (patch)
tree2d54111a8fc8ef4a892739f07990158df73c3c4e /lib
parent1de1041c00abff9cfc57837a80e12157901ff194 (diff)
downloadrails-6e638bba594b6164190d2a6fb96ffa07a20b11f3.tar.gz
rails-6e638bba594b6164190d2a6fb96ffa07a20b11f3.tar.bz2
rails-6e638bba594b6164190d2a6fb96ffa07a20b11f3.zip
Add equality to ALL THE THINGS (that matter)
People are often trying to use ARel nodes inside ActiveRecord, and when they do so, lots of things can break, because ActiveRecord relies on Array#uniq and sometimes hash key equality to handle values that end up in wheres, havings, etc. By implementing equality for all the nodes, we should hopefully be able to prevent any nodes (even nodes containing other nodes) from failing an equality check they should otherwise pass, and alleviate many of these errors. Fixes #130
Diffstat (limited to 'lib')
-rw-r--r--lib/arel/nodes/and.rb10
-rw-r--r--lib/arel/nodes/binary.rb11
-rw-r--r--lib/arel/nodes/extract.rb11
-rw-r--r--lib/arel/nodes/false.rb7
-rw-r--r--lib/arel/nodes/function.rb11
-rw-r--r--lib/arel/nodes/insert_statement.rb12
-rw-r--r--lib/arel/nodes/named_function.rb9
-rw-r--r--lib/arel/nodes/select_core.rb20
-rw-r--r--lib/arel/nodes/select_statement.rb16
-rw-r--r--lib/arel/nodes/terminal.rb7
-rw-r--r--lib/arel/nodes/true.rb7
-rw-r--r--lib/arel/nodes/unary.rb10
-rw-r--r--lib/arel/nodes/update_statement.rb15
-rw-r--r--lib/arel/nodes/window.rb30
-rw-r--r--lib/arel/table.rb13
15 files changed, 187 insertions, 2 deletions
diff --git a/lib/arel/nodes/and.rb b/lib/arel/nodes/and.rb
index b4443c3d27..0d0fb3ee82 100644
--- a/lib/arel/nodes/and.rb
+++ b/lib/arel/nodes/and.rb
@@ -18,6 +18,16 @@ module Arel
def right
children[1]
end
+
+ def hash
+ children.hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.children == other.children
+ end
+ alias :== :eql?
end
end
end
diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb
index bcd46db398..d55c7a5478 100644
--- a/lib/arel/nodes/binary.rb
+++ b/lib/arel/nodes/binary.rb
@@ -13,6 +13,17 @@ module Arel
@left = @left.clone if @left
@right = @right.clone if @right
end
+
+ def hash
+ [@left, @right].hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.left == other.left &&
+ self.right == other.right
+ end
+ alias :== :eql?
end
%w{
diff --git a/lib/arel/nodes/extract.rb b/lib/arel/nodes/extract.rb
index 1c9ee78816..92fbde62e1 100644
--- a/lib/arel/nodes/extract.rb
+++ b/lib/arel/nodes/extract.rb
@@ -18,6 +18,17 @@ module Arel
self.alias = SqlLiteral.new(aliaz)
self
end
+
+ def hash
+ super ^ [@field, @alias].hash
+ end
+
+ def eql? other
+ super &&
+ self.field == other.field &&
+ self.alias == other.alias
+ end
+ alias :== :eql?
end
end
end
diff --git a/lib/arel/nodes/false.rb b/lib/arel/nodes/false.rb
index 611e19633b..6df70e43ce 100644
--- a/lib/arel/nodes/false.rb
+++ b/lib/arel/nodes/false.rb
@@ -1,6 +1,13 @@
module Arel
module Nodes
class False < Arel::Nodes::Node
+ def hash
+ self.class.hash
+ end
+
+ def eql? other
+ self.class == other.class
+ end
end
end
end
diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb
index 5f6056a6b6..90bbf4a77b 100644
--- a/lib/arel/nodes/function.rb
+++ b/lib/arel/nodes/function.rb
@@ -16,6 +16,17 @@ module Arel
self.alias = SqlLiteral.new(aliaz)
self
end
+
+ def hash
+ [@expressions, @alias, @distinct].hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.expressions == other.expressions &&
+ self.alias == other.alias &&
+ self.distinct == other.distinct
+ end
end
%w{
diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb
index 37c12f011a..518160cce4 100644
--- a/lib/arel/nodes/insert_statement.rb
+++ b/lib/arel/nodes/insert_statement.rb
@@ -14,6 +14,18 @@ module Arel
@columns = @columns.clone
@values = @values.clone if @values
end
+
+ def hash
+ [@relation, @columns, @values].hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.relation == other.relation &&
+ self.columns == other.columns &&
+ self.values == other.values
+ end
+ alias :== :eql?
end
end
end
diff --git a/lib/arel/nodes/named_function.rb b/lib/arel/nodes/named_function.rb
index 56669bf858..c792f0af98 100644
--- a/lib/arel/nodes/named_function.rb
+++ b/lib/arel/nodes/named_function.rb
@@ -7,6 +7,15 @@ module Arel
super(expr, aliaz)
@name = name
end
+
+ def hash
+ super ^ @name.hash
+ end
+
+ def eql? other
+ super && self.name == other.name
+ end
+ alias :== :eql?
end
end
end
diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb
index 9b8c4a2a1f..3b400c768d 100644
--- a/lib/arel/nodes/select_core.rb
+++ b/lib/arel/nodes/select_core.rb
@@ -37,6 +37,26 @@ module Arel
@having = @having.clone if @having
@windows = @windows.clone
end
+
+ def hash
+ [
+ @source, @top, @set_quantifier, @projections,
+ @wheres, @groups, @having, @windows
+ ].hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.source == other.source &&
+ self.top == other.top &&
+ self.set_quantifier == other.set_quantifier &&
+ self.projections == other.projections &&
+ self.wheres == other.wheres &&
+ self.groups == other.groups &&
+ self.having == other.having &&
+ self.windows == other.windows
+ end
+ alias :== :eql?
end
end
end
diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb
index c99842f22f..32bdd7080c 100644
--- a/lib/arel/nodes/select_statement.rb
+++ b/lib/arel/nodes/select_statement.rb
@@ -5,7 +5,6 @@ module Arel
attr_accessor :limit, :orders, :lock, :offset, :with
def initialize cores = [SelectCore.new]
- #puts caller
@cores = cores
@orders = []
@limit = nil
@@ -19,6 +18,21 @@ module Arel
@cores = @cores.map { |x| x.clone }
@orders = @orders.map { |x| x.clone }
end
+
+ def hash
+ [@cores, @orders, @limit, @lock, @offset, @with].hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.cores == other.cores &&
+ self.orders == other.orders &&
+ self.limit == other.limit &&
+ self.lock == other.lock &&
+ self.offset == other.offset &&
+ self.with == other.with
+ end
+ alias :== :eql?
end
end
end
diff --git a/lib/arel/nodes/terminal.rb b/lib/arel/nodes/terminal.rb
index c6b4f4e1e2..f4cdfdfe17 100644
--- a/lib/arel/nodes/terminal.rb
+++ b/lib/arel/nodes/terminal.rb
@@ -1,6 +1,13 @@
module Arel
module Nodes
class Distinct < Arel::Nodes::Node
+ def hash
+ self.class.hash
+ end
+
+ def eql? other
+ self.class == other.class
+ end
end
end
end
diff --git a/lib/arel/nodes/true.rb b/lib/arel/nodes/true.rb
index 63dd5562e1..082963e5e6 100644
--- a/lib/arel/nodes/true.rb
+++ b/lib/arel/nodes/true.rb
@@ -1,6 +1,13 @@
module Arel
module Nodes
class True < Arel::Nodes::Node
+ def hash
+ self.class.hash
+ end
+
+ def eql? other
+ self.class == other.class
+ end
end
end
end
diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb
index 7828cceae5..42c31267dd 100644
--- a/lib/arel/nodes/unary.rb
+++ b/lib/arel/nodes/unary.rb
@@ -7,6 +7,16 @@ module Arel
def initialize expr
@expr = expr
end
+
+ def hash
+ @expr.hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.expr == other.expr
+ end
+ alias :== :eql?
end
%w{
diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb
index c08f1b2c5e..d6831dc242 100644
--- a/lib/arel/nodes/update_statement.rb
+++ b/lib/arel/nodes/update_statement.rb
@@ -18,6 +18,21 @@ module Arel
@wheres = @wheres.clone
@values = @values.clone
end
+
+ def hash
+ [@relation, @wheres, @values, @orders, @limit, @key].hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.relation == other.relation &&
+ self.wheres == other.wheres &&
+ self.values == other.values &&
+ self.orders == other.orders &&
+ self.limit == other.limit &&
+ self.key == other.key
+ end
+ alias :== :eql?
end
end
end
diff --git a/lib/arel/nodes/window.rb b/lib/arel/nodes/window.rb
index 383d6b8778..3c05f47f14 100644
--- a/lib/arel/nodes/window.rb
+++ b/lib/arel/nodes/window.rb
@@ -32,6 +32,17 @@ module Arel
super
@orders = @orders.map { |x| x.clone }
end
+
+ def hash
+ [@orders, @framing].hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.orders == other.orders &&
+ self.framing == other.framing
+ end
+ alias :== :eql?
end
class NamedWindow < Window
@@ -46,6 +57,15 @@ module Arel
super
@name = other.name.clone
end
+
+ def hash
+ super ^ @name.hash
+ end
+
+ def eql? other
+ super && self.name == other.name
+ end
+ alias :== :eql?
end
class Rows < Unary
@@ -60,7 +80,15 @@ module Arel
end
end
- class CurrentRow < Arel::Nodes::Node; end
+ class CurrentRow < Node
+ def hash
+ self.class.hash
+ end
+
+ def eql? other
+ self.class == other.class
+ end
+ end
class Preceding < Unary
def initialize(expr = nil)
diff --git a/lib/arel/table.rb b/lib/arel/table.rb
index 7a1983b3d2..6f1ab7e90f 100644
--- a/lib/arel/table.rb
+++ b/lib/arel/table.rb
@@ -123,6 +123,19 @@ Arel 4.0.0 with no replacement. PEW PEW PEW!!!
InsertManager.new(@engine)
end
+ def hash
+ [@name, @engine, @aliases, @table_alias].hash
+ end
+
+ def eql? other
+ self.class == other.class &&
+ self.name == other.name &&
+ self.engine == other.engine &&
+ self.aliases == other.aliases &&
+ self.table_alias == other.table_alias
+ end
+ alias :== :eql?
+
private
def attributes_for columns