active_record_union 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -4
- data/README.md +14 -0
- data/lib/active_record_union/active_record/relation/union.rb +6 -6
- data/lib/active_record_union/version.rb +1 -1
- data/spec/support/databases.rb +2 -0
- data/spec/support/models.rb +2 -0
- data/spec/union_spec.rb +30 -11
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae20ef21309b30f9193146326e3eaeace7cd5c51
|
4
|
+
data.tar.gz: a90fc0e536026c8d797624101090c8c91c8b9b73
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5559877947d4d9b10a37474235c2911de70c1273cc68a7bfadeea62f1f8f1477e131784752fa85bb6b9dca9cb056ff9ea059cad6477eed6316e9415731307074
|
7
|
+
data.tar.gz: 6c093a61bb9f60dc50129d0dce5a9ca83bf634471c1af8b9bba777ef1fdfb827eeddc436da14cddbaeca3720cebd1666261d48233fd063877a0dd191d1c35787
|
data/.travis.yml
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
language: ruby
|
2
2
|
addons:
|
3
|
-
postgresql: "9.
|
4
|
-
before_script:
|
5
|
-
- psql -c 'create database travis;' -U postgres # "travis" is the UNIX username, and therefore the default database name on connection
|
3
|
+
postgresql: "9.4"
|
6
4
|
rvm:
|
7
|
-
- 2.
|
5
|
+
- 2.3.0
|
6
|
+
- 2.2.4
|
7
|
+
- 2.1.8
|
8
8
|
- 2.0.0
|
data/README.md
CHANGED
@@ -7,6 +7,16 @@ Use unions on ActiveRecord scopes without ugliness.
|
|
7
7
|
|
8
8
|
If you find yourself writing `pluck(:id)` and then feeding that into another query, you may be able to reduce the number of database requests by using a nested query or a UNION without writing crazy JOIN statements.
|
9
9
|
|
10
|
+
Quick usage examples:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
current_user.posts.union(Post.published)
|
14
|
+
current_user.posts.union(Post.published).where(id: [6, 7])
|
15
|
+
current_user.posts.union("published_at < ?", Time.now)
|
16
|
+
user_1.posts.union(user_2.posts).union(Post.published)
|
17
|
+
user_1.posts.union_all(user_2.posts)
|
18
|
+
```
|
19
|
+
|
10
20
|
## Installation
|
11
21
|
|
12
22
|
Add this line to your application's Gemfile:
|
@@ -174,6 +184,10 @@ This is a gem not a Rails pull request because the standard of code quality for
|
|
174
184
|
|
175
185
|
## Changelog
|
176
186
|
|
187
|
+
**1.1.1** - Mar 19, 2016
|
188
|
+
- Fix broken polymorphic associations and joins due to improper handling of bind values. Fix by [@efradelos](https://github.com/efradelos), reported by [@Machiaweliczny](https://github.com/Machiaweliczny).
|
189
|
+
- Quote table name aliases properly. Reported by [@odedniv](https://github.com/odedniv).
|
190
|
+
|
177
191
|
**1.1.0** - Mar 29, 2015 - Add UNION ALL support, courtesy of [@pic](https://github.com/pic).
|
178
192
|
|
179
193
|
**1.0.1** - Sept 2, 2014 - Allow ORDER BY in UNION subselects for databases that support it (not SQLite).
|
@@ -3,16 +3,16 @@ module ActiveRecord
|
|
3
3
|
module Union
|
4
4
|
|
5
5
|
SET_OPERATION_TO_AREL_CLASS = {
|
6
|
-
|
7
|
-
|
6
|
+
union: Arel::Nodes::Union,
|
7
|
+
union_all: Arel::Nodes::UnionAll
|
8
8
|
}
|
9
9
|
|
10
10
|
def union(relation_or_where_arg, *args)
|
11
|
-
set_operation(
|
11
|
+
set_operation(:union, relation_or_where_arg, *args)
|
12
12
|
end
|
13
13
|
|
14
14
|
def union_all(relation_or_where_arg, *args)
|
15
|
-
set_operation(
|
15
|
+
set_operation(:union_all, relation_or_where_arg, *args)
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
@@ -37,11 +37,11 @@ module ActiveRecord
|
|
37
37
|
set = SET_OPERATION_TO_AREL_CLASS[operation].new(left, right)
|
38
38
|
from = Arel::Nodes::TableAlias.new(
|
39
39
|
set,
|
40
|
-
|
40
|
+
@klass.arel_table.name
|
41
41
|
)
|
42
42
|
|
43
43
|
relation = @klass.unscoped.from(from)
|
44
|
-
relation.bind_values = self.bind_values + other.bind_values
|
44
|
+
relation.bind_values = self.arel.bind_values + self.bind_values + other.arel.bind_values + other.bind_values
|
45
45
|
relation
|
46
46
|
end
|
47
47
|
|
data/spec/support/databases.rb
CHANGED
data/spec/support/models.rb
CHANGED
@@ -3,10 +3,12 @@ end
|
|
3
3
|
|
4
4
|
class User < ActiveRecord::Base
|
5
5
|
has_many :posts
|
6
|
+
has_many :drafts, -> { where draft: true }, class_name: "Post"
|
6
7
|
end unless defined?(User)
|
7
8
|
|
8
9
|
ActiveRecord::Base.connection.create_table :posts, force: true do |t|
|
9
10
|
t.integer :user_id
|
11
|
+
t.boolean :draft
|
10
12
|
t.timestamp :published_at
|
11
13
|
t.timestamps null: false
|
12
14
|
end
|
data/spec/union_spec.rb
CHANGED
@@ -29,10 +29,10 @@ describe ActiveRecord::Relation do
|
|
29
29
|
union = User.new(id: 1).posts.union(Post.where("created_at > ?", Time.utc(2014, 7, 19, 0, 0, 0)))
|
30
30
|
|
31
31
|
expect(union.to_sql.squish).to eq(
|
32
|
-
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) posts"
|
32
|
+
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) \"posts\""
|
33
33
|
)
|
34
34
|
expect(union.arel.to_sql.squish).to eq(
|
35
|
-
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) posts"
|
35
|
+
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) \"posts\""
|
36
36
|
)
|
37
37
|
expect{union.to_a}.to_not raise_error
|
38
38
|
end
|
@@ -43,11 +43,27 @@ describe ActiveRecord::Relation do
|
|
43
43
|
user3 = User.new(id: 3)
|
44
44
|
|
45
45
|
union = user1.posts.union(user2.posts).where.not(id: user3.posts)
|
46
|
-
|
46
|
+
|
47
|
+
# Inside ActiveRecord the bind value list is
|
48
|
+
# (union.arel.bind_values + union.bind_values)
|
49
|
+
bind_values = (union.arel.bind_values + union.bind_values).map { |column, value| value }
|
47
50
|
|
48
51
|
expect(bind_values).to eq([1, 2, 3])
|
49
52
|
end
|
50
53
|
|
54
|
+
it "binds values properly on joins" do
|
55
|
+
union = User.joins(:drafts).union(User.where(id: 11))
|
56
|
+
|
57
|
+
bind_values = (union.arel.bind_values + union.bind_values).map { |column, value| value }
|
58
|
+
expect(bind_values).to eq([true, 11])
|
59
|
+
|
60
|
+
|
61
|
+
expect(union.to_sql.squish).to eq(
|
62
|
+
"SELECT \"users\".* FROM ( SELECT \"users\".* FROM \"users\" INNER JOIN \"posts\" ON \"posts\".\"user_id\" = \"users\".\"id\" AND \"posts\".\"draft\" = 't' UNION SELECT \"users\".* FROM \"users\" WHERE \"users\".\"id\" = 11 ) \"users\""
|
63
|
+
)
|
64
|
+
expect{union.to_a}.to_not raise_error
|
65
|
+
end
|
66
|
+
|
51
67
|
it "doesn't repeat default scopes" do
|
52
68
|
expect(Time).to receive(:now) { Time.utc(2014, 7, 24, 0, 0, 0) }
|
53
69
|
|
@@ -59,7 +75,7 @@ describe ActiveRecord::Relation do
|
|
59
75
|
union = PublishedPost.where("created_at > ?", Time.utc(2014, 7, 19, 0, 0, 0)).union(User.new(id: 1).posts)
|
60
76
|
|
61
77
|
expect(union.to_sql.squish).to eq(
|
62
|
-
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE (published_at < '2014-07-24 00:00:00.000000') AND (created_at > '2014-07-19 00:00:00.000000') UNION SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ) posts"
|
78
|
+
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE (published_at < '2014-07-24 00:00:00.000000') AND (created_at > '2014-07-19 00:00:00.000000') UNION SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ) \"posts\""
|
63
79
|
)
|
64
80
|
expect{union.to_a}.to_not raise_error
|
65
81
|
end
|
@@ -74,7 +90,7 @@ describe ActiveRecord::Relation do
|
|
74
90
|
context "in SQLite" do
|
75
91
|
it "lets ORDER BY in query subselects throw a syntax error" do
|
76
92
|
expect(union.to_sql.squish).to eq(
|
77
|
-
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ORDER BY \"posts\".\"created_at\" ASC UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ORDER BY \"posts\".\"created_at\" ASC ) posts ORDER BY \"posts\".\"created_at\" ASC"
|
93
|
+
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ORDER BY \"posts\".\"created_at\" ASC UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ORDER BY \"posts\".\"created_at\" ASC ) \"posts\" ORDER BY \"posts\".\"created_at\" ASC"
|
78
94
|
)
|
79
95
|
expect{union.to_a}.to raise_error(ActiveRecord::StatementInvalid)
|
80
96
|
end
|
@@ -84,7 +100,7 @@ describe ActiveRecord::Relation do
|
|
84
100
|
it "wraps query subselects in parentheses to allow ORDER BY clauses" do
|
85
101
|
Databases.with_postgres do
|
86
102
|
expect(union.to_sql.squish).to eq(
|
87
|
-
"SELECT \"posts\".* FROM ( (SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" =
|
103
|
+
"SELECT \"posts\".* FROM ( (SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ORDER BY \"posts\".\"created_at\" ASC) UNION (SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ORDER BY \"posts\".\"created_at\" ASC) ) \"posts\" ORDER BY \"posts\".\"created_at\" ASC"
|
88
104
|
)
|
89
105
|
expect{union.to_a}.to_not raise_error
|
90
106
|
end
|
@@ -95,7 +111,7 @@ describe ActiveRecord::Relation do
|
|
95
111
|
it "wraps query subselects in parentheses to allow ORDER BY clauses" do
|
96
112
|
Databases.with_mysql do
|
97
113
|
expect(union.to_sql.squish).to eq(
|
98
|
-
"SELECT
|
114
|
+
"SELECT `posts`.* FROM ( (SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 1 ORDER BY `posts`.`created_at` ASC) UNION (SELECT `posts`.* FROM `posts` WHERE (created_at > '2014-07-19 00:00:00.000000') ORDER BY `posts`.`created_at` ASC) ) `posts` ORDER BY `posts`.`created_at` ASC"
|
99
115
|
)
|
100
116
|
expect{union.to_a}.to_not raise_error
|
101
117
|
end
|
@@ -108,24 +124,27 @@ describe ActiveRecord::Relation do
|
|
108
124
|
union = User.new(id: 1).posts.union(id: 2)
|
109
125
|
|
110
126
|
expect(union.to_sql.squish).to eq(
|
111
|
-
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\" = 2 ) posts"
|
127
|
+
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\" = 2 ) \"posts\""
|
112
128
|
)
|
129
|
+
expect{union.to_a}.to_not raise_error
|
113
130
|
end
|
114
131
|
|
115
132
|
it "multiple arguments" do
|
116
133
|
union = User.new(id: 1).posts.union("created_at > ?", Time.utc(2014, 7, 19, 0, 0, 0))
|
117
134
|
|
118
135
|
expect(union.to_sql.squish).to eq(
|
119
|
-
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) posts"
|
136
|
+
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) \"posts\""
|
120
137
|
)
|
138
|
+
expect{union.to_a}.to_not raise_error
|
121
139
|
end
|
122
140
|
|
123
141
|
it "arel" do
|
124
142
|
union = User.new(id: 1).posts.union(Post.arel_table[:id].eq(2).or(Post.arel_table[:id].eq(3)))
|
125
143
|
|
126
144
|
expect(union.to_sql.squish).to eq(
|
127
|
-
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION SELECT \"posts\".* FROM \"posts\" WHERE (\"posts\".\"id\" = 2 OR \"posts\".\"id\" = 3) ) posts"
|
145
|
+
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION SELECT \"posts\".* FROM \"posts\" WHERE (\"posts\".\"id\" = 2 OR \"posts\".\"id\" = 3) ) \"posts\""
|
128
146
|
)
|
147
|
+
expect{union.to_a}.to_not raise_error
|
129
148
|
end
|
130
149
|
end
|
131
150
|
end
|
@@ -135,7 +154,7 @@ describe ActiveRecord::Relation do
|
|
135
154
|
union = User.new(id: 1).posts.union_all(Post.where("created_at > ?", Time.utc(2014, 7, 19, 0, 0, 0)))
|
136
155
|
|
137
156
|
expect(union.to_sql.squish).to eq(
|
138
|
-
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION ALL SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) posts"
|
157
|
+
"SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION ALL SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) \"posts\""
|
139
158
|
)
|
140
159
|
expect{union.to_a}.to_not raise_error
|
141
160
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_union
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Hempel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -164,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
164
|
version: '0'
|
165
165
|
requirements: []
|
166
166
|
rubyforge_project:
|
167
|
-
rubygems_version: 2.4.5
|
167
|
+
rubygems_version: 2.4.5.1
|
168
168
|
signing_key:
|
169
169
|
specification_version: 4
|
170
170
|
summary: UNIONs in ActiveRecord! Adds proper union and union_all methods to ActiveRecord::Relation.
|