Created
August 1, 2018 09:07
-
-
Save chrisandreae/be5ad28f14b1f2a0e0c6e0098230f4bc to your computer and use it in GitHub Desktop.
ActiveRecord fails to correctly merge scopes containing IN constraints on the same column
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
begin | |
require "bundler/inline" | |
rescue LoadError => e | |
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" | |
raise e | |
end | |
gemfile(true) do | |
source "https://rubygems.org" | |
git_source(:github) { |repo| "https://github.com/#{repo}.git" } | |
gem "rails", github: "rails/rails" | |
gem "sqlite3" | |
end | |
require "active_record" | |
require "minitest/autorun" | |
require "logger" | |
# This connection will do for database-independent bug reports. | |
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") | |
ActiveRecord::Base.logger = Logger.new(STDOUT) | |
ActiveRecord::Schema.define do | |
create_table :posts, force: true do |t| | |
end | |
create_table :comments, force: true do |t| | |
t.integer :post_id | |
t.integer :value | |
end | |
end | |
class Post < ActiveRecord::Base | |
has_many :comments | |
end | |
class Comment < ActiveRecord::Base | |
belongs_to :post | |
end | |
class BugTest < Minitest::Test | |
def setup | |
Post.create!([{ id: 1 }, { id: 2 }, { id: 3 }]) | |
assert_equal 3, Post.count | |
Comment.create!([{ post_id: 1, value: 1 }, | |
{ post_id: 2, value: 1 }, { post_id: 2, value: 2 }, | |
{ post_id: 3, value: 2 }]) | |
assert_equal 4, Comment.count | |
end | |
def teardown | |
Comment.delete_all | |
Post.delete_all | |
end | |
# Merging relational constraints works: | |
def test_merging_relational_constraints | |
posts = Post.where(Post.arel_table[:id].gt(1)) | |
.merge(Post.where(Post.arel_table[:id].lt(3))) | |
assert_equal 1, posts.count # passes | |
end | |
# But merging IN constraints doesn't work: | |
def test_merging_in_constraints | |
posts = Post.where(id: [2, 3]).where(id: [1, 2]) | |
assert_equal 1, posts.count # passes | |
posts = Post.where(id: [2, 3]) | |
.merge(Post.where(id: [1, 2])) | |
assert_equal 1, posts.count # fails | |
end | |
# It also fails when using arel explicitly: | |
def test_merging_arel_in_constraints | |
posts = Post.where(Post.arel_table[:id].in([2, 3])) | |
.where(Post.arel_table[:id].in([1, 2])) | |
assert_equal 1, posts.count # passes | |
posts = Post.where(Post.arel_table[:id].in([2, 3])) | |
.merge(Post.where(Post.arel_table[:id].in([1, 2]))) | |
assert_equal 1, posts.count # fails | |
end | |
# and when using subquery IN constraints | |
def test_merging_subquery_in_constraints | |
posts = Post.where(id: Comment.where(value: 1).select(:post_id)) | |
.where(id: Comment.where(value: 2).select(:post_id)) | |
assert_equal 1, posts.count # passes | |
posts = Post.where(id: Comment.where(value: 1).select(:post_id)) | |
.merge(Post.where(id: Comment.where(value: 2).select(:post_id))) | |
assert_equal 1, posts.count # fails | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment