active_record_union 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.
|