aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/relation
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test/cases/relation')
-rw-r--r--activerecord/test/cases/relation/mutation_test.rb10
-rw-r--r--activerecord/test/cases/relation/where_chain_test.rb72
-rw-r--r--activerecord/test/cases/relation/where_clause_test.rb128
3 files changed, 169 insertions, 41 deletions
diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb
index 2443f10269..45ead08bd5 100644
--- a/activerecord/test/cases/relation/mutation_test.rb
+++ b/activerecord/test/cases/relation/mutation_test.rb
@@ -81,7 +81,7 @@ module ActiveRecord
assert_equal [], relation.extending_values
end
- (Relation::SINGLE_VALUE_METHODS - [:from, :lock, :reordering, :reverse_order, :create_with]).each do |method|
+ (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with]).each do |method|
test "##{method}!" do
assert relation.public_send("#{method}!", :foo).equal?(relation)
assert_equal :foo, relation.public_send("#{method}_value")
@@ -90,7 +90,7 @@ module ActiveRecord
test '#from!' do
assert relation.from!('foo').equal?(relation)
- assert_equal ['foo', nil], relation.from_value
+ assert_equal 'foo', relation.from_clause.value
end
test '#lock!' do
@@ -136,12 +136,12 @@ module ActiveRecord
end
test 'test_merge!' do
- assert relation.merge!(where: :foo).equal?(relation)
- assert_equal [:foo], relation.where_values
+ assert relation.merge!(select: :foo).equal?(relation)
+ assert_equal [:foo], relation.select_values
end
test 'merge with a proc' do
- assert_equal [:foo], relation.merge(-> { where(:foo) }).where_values
+ assert_equal [:foo], relation.merge(-> { select(:foo) }).select_values
end
test 'none!' do
diff --git a/activerecord/test/cases/relation/where_chain_test.rb b/activerecord/test/cases/relation/where_chain_test.rb
index 0f9019bb1b..00c9a001c0 100644
--- a/activerecord/test/cases/relation/where_chain_test.rb
+++ b/activerecord/test/cases/relation/where_chain_test.rb
@@ -14,10 +14,10 @@ module ActiveRecord
def test_not_eq
relation = Post.where.not(title: 'hello')
- assert_equal 1, relation.where_values.length
+ assert_equal 1, relation.where_clause.predicates.length
- value = relation.where_values.first
- bind = relation.bind_values.first
+ value = relation.where_clause.predicates.first
+ bind = relation.where_clause.binds.first
assert_bound_ast value, Post.arel_table[@name], Arel::Nodes::NotEqual
assert_equal 'hello', bind.last
@@ -26,7 +26,7 @@ module ActiveRecord
def test_not_null
expected = Post.arel_table[@name].not_eq(nil)
relation = Post.where.not(title: nil)
- assert_equal([expected], relation.where_values)
+ assert_equal([expected], relation.where_clause.predicates)
end
def test_not_with_nil
@@ -38,25 +38,25 @@ module ActiveRecord
def test_not_in
expected = Post.arel_table[@name].not_in(%w[hello goodbye])
relation = Post.where.not(title: %w[hello goodbye])
- assert_equal([expected], relation.where_values)
+ assert_equal([expected], relation.where_clause.predicates)
end
def test_association_not_eq
expected = Comment.arel_table[@name].not_eq(Arel::Nodes::BindParam.new)
relation = Post.joins(:comments).where.not(comments: {title: 'hello'})
- assert_equal(expected.to_sql, relation.where_values.first.to_sql)
+ assert_equal(expected.to_sql, relation.where_clause.predicates.first.to_sql)
end
def test_not_eq_with_preceding_where
relation = Post.where(title: 'hello').where.not(title: 'world')
- value = relation.where_values.first
- bind = relation.bind_values.first
+ value = relation.where_clause.predicates.first
+ bind = relation.where_clause.binds.first
assert_bound_ast value, Post.arel_table[@name], Arel::Nodes::Equality
assert_equal 'hello', bind.last
- value = relation.where_values.last
- bind = relation.bind_values.last
+ value = relation.where_clause.predicates.last
+ bind = relation.where_clause.binds.last
assert_bound_ast value, Post.arel_table[@name], Arel::Nodes::NotEqual
assert_equal 'world', bind.last
end
@@ -64,13 +64,13 @@ module ActiveRecord
def test_not_eq_with_succeeding_where
relation = Post.where.not(title: 'hello').where(title: 'world')
- value = relation.where_values.first
- bind = relation.bind_values.first
+ value = relation.where_clause.predicates.first
+ bind = relation.where_clause.binds.first
assert_bound_ast value, Post.arel_table[@name], Arel::Nodes::NotEqual
assert_equal 'hello', bind.last
- value = relation.where_values.last
- bind = relation.bind_values.last
+ value = relation.where_clause.predicates.last
+ bind = relation.where_clause.binds.last
assert_bound_ast value, Post.arel_table[@name], Arel::Nodes::Equality
assert_equal 'world', bind.last
end
@@ -78,23 +78,23 @@ module ActiveRecord
def test_not_eq_with_string_parameter
expected = Arel::Nodes::Not.new("title = 'hello'")
relation = Post.where.not("title = 'hello'")
- assert_equal([expected], relation.where_values)
+ assert_equal([expected], relation.where_clause.predicates)
end
def test_not_eq_with_array_parameter
expected = Arel::Nodes::Not.new("title = 'hello'")
relation = Post.where.not(['title = ?', 'hello'])
- assert_equal([expected], relation.where_values)
+ assert_equal([expected], relation.where_clause.predicates)
end
def test_chaining_multiple
relation = Post.where.not(author_id: [1, 2]).where.not(title: 'ruby on rails')
expected = Post.arel_table['author_id'].not_in([1, 2])
- assert_equal(expected, relation.where_values[0])
+ assert_equal(expected, relation.where_clause.predicates[0])
- value = relation.where_values[1]
- bind = relation.bind_values.first
+ value = relation.where_clause.predicates[1]
+ bind = relation.where_clause.binds.first
assert_bound_ast value, Post.arel_table[@name], Arel::Nodes::NotEqual
assert_equal 'ruby on rails', bind.last
@@ -103,9 +103,9 @@ module ActiveRecord
def test_rewhere_with_one_condition
relation = Post.where(title: 'hello').where(title: 'world').rewhere(title: 'alone')
- assert_equal 1, relation.where_values.size
- value = relation.where_values.first
- bind = relation.bind_values.first
+ assert_equal 1, relation.where_clause.predicates.size
+ value = relation.where_clause.predicates.first
+ bind = relation.where_clause.binds.first
assert_bound_ast value, Post.arel_table[@name], Arel::Nodes::Equality
assert_equal 'alone', bind.last
end
@@ -113,15 +113,15 @@ module ActiveRecord
def test_rewhere_with_multiple_overwriting_conditions
relation = Post.where(title: 'hello').where(body: 'world').rewhere(title: 'alone', body: 'again')
- assert_equal 2, relation.where_values.size
+ assert_equal 2, relation.where_clause.predicates.size
- value = relation.where_values.first
- bind = relation.bind_values.first
+ value = relation.where_clause.predicates.first
+ bind = relation.where_clause.binds.first
assert_bound_ast value, Post.arel_table['title'], Arel::Nodes::Equality
assert_equal 'alone', bind.last
- value = relation.where_values[1]
- bind = relation.bind_values[1]
+ value = relation.where_clause.predicates[1]
+ bind = relation.where_clause.binds[1]
assert_bound_ast value, Post.arel_table['body'], Arel::Nodes::Equality
assert_equal 'again', bind.last
end
@@ -135,16 +135,16 @@ module ActiveRecord
def test_rewhere_with_one_overwriting_condition_and_one_unrelated
relation = Post.where(title: 'hello').where(body: 'world').rewhere(title: 'alone')
- assert_equal 2, relation.where_values.size
+ assert_equal 2, relation.where_clause.predicates.size
- value = relation.where_values.first
- bind = relation.bind_values.first
+ value = relation.where_clause.predicates.first
+ bind = relation.where_clause.binds.first
assert_bound_ast value, Post.arel_table['body'], Arel::Nodes::Equality
assert_equal 'world', bind.last
- value = relation.where_values.second
- bind = relation.bind_values.second
+ value = relation.where_clause.predicates.second
+ bind = relation.where_clause.binds.second
assert_bound_ast value, Post.arel_table['title'], Arel::Nodes::Equality
assert_equal 'alone', bind.last
@@ -153,28 +153,28 @@ module ActiveRecord
def test_rewhere_with_range
relation = Post.where(comments_count: 1..3).rewhere(comments_count: 3..5)
- assert_equal 1, relation.where_values.size
+ assert_equal 1, relation.where_clause.predicates.size
assert_equal Post.where(comments_count: 3..5), relation
end
def test_rewhere_with_infinite_upper_bound_range
relation = Post.where(comments_count: 1..Float::INFINITY).rewhere(comments_count: 3..5)
- assert_equal 1, relation.where_values.size
+ assert_equal 1, relation.where_clause.predicates.size
assert_equal Post.where(comments_count: 3..5), relation
end
def test_rewhere_with_infinite_lower_bound_range
relation = Post.where(comments_count: -Float::INFINITY..1).rewhere(comments_count: 3..5)
- assert_equal 1, relation.where_values.size
+ assert_equal 1, relation.where_clause.predicates.size
assert_equal Post.where(comments_count: 3..5), relation
end
def test_rewhere_with_infinite_range
relation = Post.where(comments_count: -Float::INFINITY..Float::INFINITY).rewhere(comments_count: 3..5)
- assert_equal 1, relation.where_values.size
+ assert_equal 1, relation.where_clause.predicates.size
assert_equal Post.where(comments_count: 3..5), relation
end
end
diff --git a/activerecord/test/cases/relation/where_clause_test.rb b/activerecord/test/cases/relation/where_clause_test.rb
new file mode 100644
index 0000000000..6864be2608
--- /dev/null
+++ b/activerecord/test/cases/relation/where_clause_test.rb
@@ -0,0 +1,128 @@
+require "cases/helper"
+
+class ActiveRecord::Relation
+ class WhereClauseTest < ActiveRecord::TestCase
+ test "+ combines two where clauses" do
+ first_clause = WhereClause.new([table["id"].eq(bind_param)], [["id", 1]])
+ second_clause = WhereClause.new([table["name"].eq(bind_param)], [["name", "Sean"]])
+ combined = WhereClause.new(
+ [table["id"].eq(bind_param), table["name"].eq(bind_param)],
+ [["id", 1], ["name", "Sean"]],
+ )
+
+ assert_equal combined, first_clause + second_clause
+ end
+
+ test "+ is associative, but not commutative" do
+ a = WhereClause.new(["a"], ["bind a"])
+ b = WhereClause.new(["b"], ["bind b"])
+ c = WhereClause.new(["c"], ["bind c"])
+
+ assert_equal a + (b + c), (a + b) + c
+ assert_not_equal a + b, b + a
+ end
+
+ test "an empty where clause is the identity value for +" do
+ clause = WhereClause.new([table["id"].eq(bind_param)], [["id", 1]])
+
+ assert_equal clause, clause + WhereClause.empty
+ end
+
+ test "merge combines two where clauses" do
+ a = WhereClause.new([table["id"].eq(1)], [])
+ b = WhereClause.new([table["name"].eq("Sean")], [])
+ expected = WhereClause.new([table["id"].eq(1), table["name"].eq("Sean")], [])
+
+ assert_equal expected, a.merge(b)
+ end
+
+ test "merge keeps the right side, when two equality clauses reference the same column" do
+ a = WhereClause.new([table["id"].eq(1), table["name"].eq("Sean")], [])
+ b = WhereClause.new([table["name"].eq("Jim")], [])
+ expected = WhereClause.new([table["id"].eq(1), table["name"].eq("Jim")], [])
+
+ assert_equal expected, a.merge(b)
+ end
+
+ test "merge removes bind parameters matching overlapping equality clauses" do
+ a = WhereClause.new(
+ [table["id"].eq(bind_param), table["name"].eq(bind_param)],
+ [[column("id"), 1], [column("name"), "Sean"]],
+ )
+ b = WhereClause.new(
+ [table["name"].eq(bind_param)],
+ [[column("name"), "Jim"]]
+ )
+ expected = WhereClause.new(
+ [table["id"].eq(bind_param), table["name"].eq(bind_param)],
+ [[column("id"), 1], [column("name"), "Jim"]],
+ )
+
+ assert_equal expected, a.merge(b)
+ end
+
+ test "merge allows for columns with the same name from different tables" do
+ skip "This is not possible as of 4.2, and the binds do not yet contain sufficient information for this to happen"
+ # We might be able to change the implementation to remove conflicts by index, rather than column name
+ end
+
+ test "a clause knows if it is empty" do
+ assert WhereClause.empty.empty?
+ assert_not WhereClause.new(["anything"], []).empty?
+ end
+
+ test "invert cannot handle nil" do
+ where_clause = WhereClause.new([nil], [])
+
+ assert_raises ArgumentError do
+ where_clause.invert
+ end
+ end
+
+ test "invert replaces each part of the predicate with its inverse" do
+ random_object = Object.new
+ original = WhereClause.new([
+ table["id"].in([1, 2, 3]),
+ table["id"].eq(1),
+ "sql literal",
+ random_object
+ ], [])
+ expected = WhereClause.new([
+ table["id"].not_in([1, 2, 3]),
+ table["id"].not_eq(1),
+ Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new("sql literal")),
+ Arel::Nodes::Not.new(random_object)
+ ], [])
+
+ assert_equal expected, original.invert
+ end
+
+ test "accept removes binary predicates referencing a given column" do
+ where_clause = WhereClause.new([
+ table["id"].in([1, 2, 3]),
+ table["name"].eq(bind_param),
+ table["age"].gteq(bind_param),
+ ], [
+ [column("name"), "Sean"],
+ [column("age"), 30],
+ ])
+ expected = WhereClause.new([table["age"].gteq(bind_param)], [[column("age"), 30]])
+
+ assert_equal expected, where_clause.except("id", "name")
+ end
+
+ private
+
+ def table
+ Arel::Table.new("table")
+ end
+
+ def bind_param
+ Arel::Nodes::BindParam.new
+ end
+
+ def column(name)
+ ActiveRecord::ConnectionAdapters::Column.new(name, nil, nil)
+ end
+ end
+end