提交 5136277f 编写于 作者: R Ryuta Kamizono

Allow `unscope` to be aware of table name qualified values

It is possible to unscope only the column in the specified table.

```ruby
posts = Post.joins(:comments).group(:"posts.hidden")
posts = posts.where("posts.hidden": false, "comments.hidden": false)

posts.count
# => { false => 10 }

# unscope both hidden columns
posts.unscope(where: :hidden).count
# => { false => 11, true => 1 }

# unscope only comments.hidden column
posts.unscope(where: :"comments.hidden").count
# => { false => 11 }
```
Co-authored-by: NSlava Korolev <korolvs@gmail.com>
上级 d22216f2
* Allow `unscope` to be aware of table name qualified values.
It is possible to unscope only the column in the specified table.
```ruby
posts = Post.joins(:comments).group(:"posts.hidden")
posts = posts.where("posts.hidden": false, "comments.hidden": false)
posts.count
# => { false => 10 }
# unscope both hidden columns
posts.unscope(where: :hidden).count
# => { false => 11, true => 1 }
# unscope only comments.hidden column
posts.unscope(where: :"comments.hidden").count
# => { false => 11 }
```
*Ryuta Kamizono*, *Slava Korolev*
* Fix `rewhere` to truly overwrite collided where clause by new where clause.
```ruby
......
......@@ -62,6 +62,10 @@ def build_bind_attribute(column_name, value)
Arel::Nodes::BindParam.new(attr)
end
def resolve_arel_attribute(table_name, column_name)
table.associated_table(table_name).arel_attribute(column_name)
end
protected
def expand_from_hash(attributes)
return ["1=0"] if attributes.empty?
......
......@@ -483,7 +483,7 @@ def unscope!(*args) # :nodoc:
raise ArgumentError, "Hash arguments in .unscope(*args) must have :where as the key."
end
target_values = Array(target_value)
target_values = resolve_arel_attributes(Array.wrap(target_value))
self.where_clause = where_clause.except(*target_values)
end
else
......@@ -1399,6 +1399,30 @@ def order_column(field)
end
end
def resolve_arel_attributes(attrs)
attrs.flat_map do |attr|
case attr
when Arel::Attributes::Attribute
attr
when Hash
attr.flat_map do |table, columns|
table = table.to_s
Array(columns).map do |column|
predicate_builder.resolve_arel_attribute(table, column)
end
end
else
attr = attr.to_s
if attr.include?(".")
table, column = attr.split(".", 2)
predicate_builder.resolve_arel_attribute(table, column)
else
attr
end
end
end
end
# Checks to make sure that the arguments are not blank. Note that if some
# blank-like object were initially passed into the query method, then this
# method will not raise an error.
......
......@@ -2050,6 +2050,36 @@ def test_unscope_specific_where_value
assert_equal 1, posts.unscope(where: :body).count
end
def test_unscope_with_aliased_column
posts = Post.where(author: authors(:mary), text: "hullo").order(:id)
assert_equal [posts(:misc_by_mary)], posts
posts = posts.unscope(where: :"posts.text")
assert_equal posts(:eager_other, :misc_by_mary, :other_by_mary), posts
end
def test_unscope_with_table_name_qualified_column
comments = Comment.joins(:post).where("posts.id": posts(:thinking))
assert_equal [comments(:does_it_hurt)], comments
comments = comments.where(id: comments(:greetings))
assert_empty comments
comments = comments.unscope(where: :"posts.id")
assert_equal [comments(:greetings)], comments
end
def test_unscope_with_table_name_qualified_hash
comments = Comment.joins(:post).where("posts.id": posts(:thinking))
assert_equal [comments(:does_it_hurt)], comments
comments = comments.where(id: comments(:greetings))
assert_empty comments
comments = comments.unscope(where: { posts: :id })
assert_equal [comments(:greetings)], comments
end
def test_unscope_with_arel_sql
posts = Post.where(Arel.sql("'Welcome to the weblog'").eq(Post.arel_attribute(:title)))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册