aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/relation.rb7
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb34
-rw-r--r--activerecord/lib/active_record/relation/where_clause.rb29
-rw-r--r--activerecord/test/cases/relation/where_clause_test.rb41
-rw-r--r--activerecord/test/cases/relation_test.rb10
5 files changed, 110 insertions, 11 deletions
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 9c4db8a05e..54cb6861b8 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -1,18 +1,19 @@
# -*- coding: utf-8 -*-
-require 'arel/collectors/bind'
+require "arel/collectors/bind"
module ActiveRecord
# = Active Record Relation
class Relation
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
- :order, :joins, :where, :having, :bind, :references,
+ :order, :joins, :having, :references,
:extending, :unscope]
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
:reverse_order, :distinct, :create_with, :uniq]
+ CLAUSE_METHODS = [:where]
INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
- VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
+ VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index e1c74ce90a..9a636bc527 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/string/filters'
require 'active_model/forbidden_attributes_protection'
+require "active_record/relation/where_clause"
module ActiveRecord
module QueryMethods
@@ -90,6 +91,35 @@ module ActiveRecord
CODE
end
+ Relation::CLAUSE_METHODS.each do |name|
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{name}_clause # def where_clause
+ @values[:#{name}] || new_#{name}_clause # @values[:where] || new_where_clause
+ end # end
+ #
+ def #{name}_clause=(value) # def where_clause=(value)
+ assert_mutability! # assert_mutability!
+ @values[:#{name}] = value # @values[:where] = value
+ end # end
+ CODE
+ end
+
+ def where_values
+ where_clause.parts
+ end
+
+ def where_values=(values)
+ self.where_clause = Relation::WhereClause.new(values || [], where_clause.binds)
+ end
+
+ def bind_values
+ where_clause.binds
+ end
+
+ def bind_values=(values)
+ self.where_clause = Relation::WhereClause.new(where_clause.parts, values || [])
+ end
+
def create_with_value # :nodoc:
@values[:create_with] || {}
end
@@ -1117,5 +1147,9 @@ module ActiveRecord
raise ArgumentError, "The method .#{method_name}() must contain arguments."
end
end
+
+ def new_where_clause
+ Relation::WhereClause.empty
+ end
end
end
diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb
new file mode 100644
index 0000000000..b39fc1fed1
--- /dev/null
+++ b/activerecord/lib/active_record/relation/where_clause.rb
@@ -0,0 +1,29 @@
+module ActiveRecord
+ class Relation
+ class WhereClause
+ attr_reader :parts, :binds
+
+ def initialize(parts, binds)
+ @parts = parts
+ @binds = binds
+ end
+
+ def +(other)
+ WhereClause.new(
+ parts + other.parts,
+ binds + other.binds,
+ )
+ end
+
+ def ==(other)
+ other.is_a?(WhereClause) &&
+ parts == other.parts &&
+ binds == other.binds
+ end
+
+ def self.empty
+ new([], [])
+ end
+ end
+ 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..66e2f3ab48
--- /dev/null
+++ b/activerecord/test/cases/relation/where_clause_test.rb
@@ -0,0 +1,41 @@
+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
+
+ private
+
+ def table
+ Arel::Table.new("table")
+ end
+
+ def bind_param
+ Arel::Nodes::BindParam.new
+ end
+ end
+end
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index f7cb471984..75d74ddc7b 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -177,14 +177,8 @@ module ActiveRecord
end
test 'relations can be created with a values hash' do
- relation = Relation.new(FakeKlass, :b, nil, where: [:foo])
- assert_equal [:foo], relation.where_values
- end
-
- test 'merging a single where value' do
- relation = Relation.new(FakeKlass, :b, nil)
- relation.merge!(where: :foo)
- assert_equal [:foo], relation.where_values
+ relation = Relation.new(FakeKlass, :b, nil, select: [:foo])
+ assert_equal [:foo], relation.select_values
end
test 'merging a hash interpolates conditions' do