arel-helpers 2.9.1 → 2.12.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/Gemfile +1 -14
- data/README.md +28 -2
- data/arel-helpers.gemspec +15 -12
- data/lib/arel-helpers/join_association.rb +87 -29
- data/lib/arel-helpers/query_builder.rb +15 -0
- data/lib/arel-helpers/version.rb +1 -1
- data/spec/aliases_spec.rb +5 -7
- data/spec/arel_table_spec.rb +11 -13
- data/spec/env/models.rb +2 -6
- data/spec/internal/config/database.yml +3 -0
- data/spec/internal/db/combustion_test.sqlite +0 -0
- data/spec/internal/db/schema.rb +34 -0
- data/spec/internal/log/test.log +393 -0
- data/spec/join_association_spec.rb +101 -57
- data/spec/query_builder_spec.rb +31 -18
- data/spec/spec_helper.rb +10 -20
- metadata +94 -9
- data/spec/env/migrations.rb +0 -75
- data/spec/env.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20ee0a4bd3c483dbe5dc58fa930700f36a09e593faf1982f0c578e5adb4736e4
|
4
|
+
data.tar.gz: 26195a43b12121bb2ef5d4bbee9ebe9e95ce70769e24206892a04cd04d76cc25
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e40a55ba798ac3c094a44aaf0d9dce31cf6ce12adca9a5e2b45f225696f69dfcbc1cb8b517ea984113ad888392b519b4d98538fd904f3cb4bdbfe7772cac5c7
|
7
|
+
data.tar.gz: 409ebbdbaedef2216bc68579f562dcfa44dfb2dcf7b0b4275599fee2c11f3e165674237cf882c4aef31e651069079649a04e583ac15a06a9ebfc39c3b0b48b98
|
data/Gemfile
CHANGED
@@ -1,16 +1,3 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
gemspec
|
4
|
-
|
5
|
-
group :development, :test do
|
6
|
-
gem 'pry-byebug'
|
7
|
-
|
8
|
-
# lock to 10.0 until rspec is upgraded
|
9
|
-
gem 'rake', '~> 10.0'
|
10
|
-
end
|
11
|
-
|
12
|
-
group :test do
|
13
|
-
gem 'rspec', '~> 2.11.0'
|
14
|
-
gem 'rr', '~> 1.0.4'
|
15
|
-
gem 'sqlite3'
|
16
|
-
end
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+

|
2
2
|
|
3
3
|
## arel-helpers [](http://travis-ci.org/camertron/arel-helpers)
|
4
4
|
|
@@ -187,9 +187,35 @@ PostQueryBuilder.new
|
|
187
187
|
.since_yesterday
|
188
188
|
```
|
189
189
|
|
190
|
+
#### Conditional reflections
|
191
|
+
|
192
|
+
If you have parts of a query that should only be added under certain conditions you can return `reflect(query)` from your method. E.g:
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
def with_comments_by(usernames)
|
196
|
+
if usernames
|
197
|
+
reflect(
|
198
|
+
query.where(post[:title].matches("%#{title}%"))
|
199
|
+
)
|
200
|
+
else
|
201
|
+
reflect(query)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
```
|
205
|
+
|
206
|
+
This can become repetitive, and as an alternative you can choose to prepend `not_nil` to your method definition:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
class PostQueryBuilder < ArelHelpers::QueryBuilder
|
210
|
+
not_nil def with_comments_by(usernames)
|
211
|
+
reflect(query.where(post[:title].matches("%#{title}%"))) if usernames
|
212
|
+
end
|
213
|
+
end
|
214
|
+
```
|
215
|
+
|
190
216
|
## Requirements
|
191
217
|
|
192
|
-
Requires ActiveRecord >= 3.1.0, <
|
218
|
+
Requires ActiveRecord >= 3.1.0, < 7. Depends on SQLite for testing purposes.
|
193
219
|
|
194
220
|
## Running Tests
|
195
221
|
|
data/arel-helpers.gemspec
CHANGED
@@ -1,23 +1,26 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'lib')
|
2
2
|
require 'arel-helpers/version'
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
|
-
s.name =
|
5
|
+
s.name = 'arel-helpers'
|
6
6
|
s.version = ::ArelHelpers::VERSION
|
7
|
-
s.authors = [
|
8
|
-
s.email = [
|
9
|
-
s.homepage =
|
7
|
+
s.authors = ['Cameron Dutro']
|
8
|
+
s.email = ['camertron@gmail.com']
|
9
|
+
s.homepage = 'https://github.com/camertron/arel-helpers'
|
10
10
|
s.license = 'MIT'
|
11
|
-
s.description = s.summary =
|
11
|
+
s.description = s.summary = 'Useful tools to help construct database queries with ActiveRecord and Arel.'
|
12
12
|
|
13
13
|
s.platform = Gem::Platform::RUBY
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
s.add_dependency 'activerecord', '>= 3.1.0', '< 7'
|
16
|
+
|
17
|
+
s.add_development_dependency 'appraisal'
|
18
|
+
s.add_development_dependency 'combustion', '~> 1.3'
|
19
|
+
s.add_development_dependency 'database_cleaner', '~> 1.8'
|
20
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
21
|
+
s.add_development_dependency 'rspec', '~> 3'
|
22
|
+
s.add_development_dependency 'sqlite3', '~> 1.4.0'
|
20
23
|
|
21
24
|
s.require_path = 'lib'
|
22
|
-
s.files = Dir[
|
25
|
+
s.files = Dir['{lib,spec}/**/*', 'Gemfile', 'History.txt', 'README.md', 'Rakefile', 'arel-helpers.gemspec']
|
23
26
|
end
|
@@ -18,7 +18,11 @@ module ArelHelpers
|
|
18
18
|
# This method encapsulates that functionality and yields an intermediate object for chaining.
|
19
19
|
# It also allows you to use an outer join instead of the default inner via the join_type arg.
|
20
20
|
def join_association(table, association, join_type = Arel::Nodes::InnerJoin, options = {}, &block)
|
21
|
-
if version >= '
|
21
|
+
if version >= '6.1.0'
|
22
|
+
join_association_6_1_0(table, association, join_type, options, &block)
|
23
|
+
elsif version >= '6.0.0'
|
24
|
+
join_association_6_0_0(table, association, join_type, options, &block)
|
25
|
+
elsif version >= '5.2.1'
|
22
26
|
join_association_5_2_1(table, association, join_type, options, &block)
|
23
27
|
elsif version >= '5.2.0'
|
24
28
|
join_association_5_2(table, association, join_type, options, &block)
|
@@ -40,7 +44,7 @@ module ArelHelpers
|
|
40
44
|
end
|
41
45
|
|
42
46
|
def join_association_3_1(table, association, join_type, options = {})
|
43
|
-
aliases = options.fetch(:aliases,
|
47
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
44
48
|
associations = association.is_a?(Array) ? association : [association]
|
45
49
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(table, associations, [])
|
46
50
|
manager = Arel::SelectManager.new(table)
|
@@ -51,12 +55,9 @@ module ArelHelpers
|
|
51
55
|
end
|
52
56
|
|
53
57
|
manager.join_sources.map do |assoc|
|
54
|
-
|
55
|
-
assoc.left.table_alias = found_alias.name
|
56
|
-
end
|
58
|
+
assoc.left.table_alias = aliases[assoc.left.name].name if aliases.key?(assoc.left.name)
|
57
59
|
|
58
60
|
if block_given?
|
59
|
-
# yield |assoc_name, join_conditions|
|
60
61
|
right = yield assoc.left.name.to_sym, assoc.right
|
61
62
|
assoc.class.new(assoc.left, right)
|
62
63
|
else
|
@@ -66,7 +67,7 @@ module ArelHelpers
|
|
66
67
|
end
|
67
68
|
|
68
69
|
def join_association_4_1(table, association, join_type, options = {})
|
69
|
-
aliases = options.fetch(:aliases,
|
70
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
70
71
|
associations = association.is_a?(Array) ? association : [association]
|
71
72
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(table, associations, [])
|
72
73
|
|
@@ -77,9 +78,7 @@ module ArelHelpers
|
|
77
78
|
constraint.right
|
78
79
|
end
|
79
80
|
|
80
|
-
|
81
|
-
constraint.left.table_alias = found_alias.name
|
82
|
-
end
|
81
|
+
constraint.left.table_alias = aliases[constraint.left.name].name if aliases.key?(constraint.left.name)
|
83
82
|
|
84
83
|
join_type.new(constraint.left, right)
|
85
84
|
end
|
@@ -91,7 +90,7 @@ module ArelHelpers
|
|
91
90
|
# dynamically. To get around the problem, this method must return
|
92
91
|
# a string.
|
93
92
|
def join_association_4_2(table, association, join_type, options = {})
|
94
|
-
aliases = options.fetch(:aliases, [])
|
93
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
95
94
|
associations = association.is_a?(Array) ? association : [association]
|
96
95
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(table, associations, [])
|
97
96
|
|
@@ -109,9 +108,7 @@ module ArelHelpers
|
|
109
108
|
join.right
|
110
109
|
end
|
111
110
|
|
112
|
-
|
113
|
-
join.left.table_alias = found_alias.name
|
114
|
-
end
|
111
|
+
join.left.table_alias = aliases[join.left.name].name if aliases.key?(join.left.name)
|
115
112
|
|
116
113
|
join_type.new(join.left, right)
|
117
114
|
end
|
@@ -125,7 +122,7 @@ module ArelHelpers
|
|
125
122
|
end
|
126
123
|
|
127
124
|
def join_association_5_0(table, association, join_type, options = {})
|
128
|
-
aliases = options.fetch(:aliases, [])
|
125
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
129
126
|
associations = association.is_a?(Array) ? association : [association]
|
130
127
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(table, associations, [])
|
131
128
|
|
@@ -144,9 +141,7 @@ module ArelHelpers
|
|
144
141
|
join.right
|
145
142
|
end
|
146
143
|
|
147
|
-
|
148
|
-
join.left.table_alias = found_alias.name
|
149
|
-
end
|
144
|
+
join.left.table_alias = aliases[join.left.name].name if aliases.key?(join.left.name)
|
150
145
|
|
151
146
|
join_type.new(join.left, right)
|
152
147
|
end
|
@@ -160,7 +155,7 @@ module ArelHelpers
|
|
160
155
|
end
|
161
156
|
|
162
157
|
def join_association_5_2(table, association, join_type, options = {})
|
163
|
-
aliases = options.fetch(:aliases, [])
|
158
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
164
159
|
associations = association.is_a?(Array) ? association : [association]
|
165
160
|
|
166
161
|
alias_tracker = ActiveRecord::Associations::AliasTracker.create(
|
@@ -180,16 +175,14 @@ module ArelHelpers
|
|
180
175
|
join.right
|
181
176
|
end
|
182
177
|
|
183
|
-
|
184
|
-
join.left.table_alias = found_alias.name
|
185
|
-
end
|
178
|
+
join.left.table_alias = aliases[join.left.name].name if aliases.key?(join.left.name)
|
186
179
|
|
187
180
|
join_type.new(join.left, right)
|
188
181
|
end
|
189
182
|
end
|
190
183
|
|
191
184
|
def join_association_5_2_1(table, association, join_type, options = {})
|
192
|
-
aliases = options.fetch(:aliases, [])
|
185
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
193
186
|
associations = association.is_a?(Array) ? association : [association]
|
194
187
|
|
195
188
|
alias_tracker = ActiveRecord::Associations::AliasTracker.create(
|
@@ -209,14 +202,83 @@ module ArelHelpers
|
|
209
202
|
join.right
|
210
203
|
end
|
211
204
|
|
212
|
-
|
213
|
-
|
205
|
+
join.left.table_alias = aliases[join.left.name].name if aliases.key?(join.left.name)
|
206
|
+
|
207
|
+
join_type.new(join.left, right)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def join_association_6_0_0(table, association, join_type, options = {})
|
212
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
213
|
+
associations = association.is_a?(Array) ? association : [association]
|
214
|
+
|
215
|
+
alias_tracker = ActiveRecord::Associations::AliasTracker.create(
|
216
|
+
table.connection, table.name, {}
|
217
|
+
)
|
218
|
+
|
219
|
+
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
220
|
+
table, table.arel_table, associations, join_type
|
221
|
+
)
|
222
|
+
|
223
|
+
constraints = join_dependency.join_constraints([], alias_tracker)
|
224
|
+
|
225
|
+
constraints.map do |join|
|
226
|
+
right = if block_given?
|
227
|
+
yield join.left.name.to_sym, join.right
|
228
|
+
else
|
229
|
+
join.right
|
214
230
|
end
|
215
231
|
|
232
|
+
join.left.table_alias = aliases[join.left.name].name if aliases.key?(join.left.name)
|
233
|
+
|
234
|
+
join_type.new(join.left, right)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def join_association_6_1_0(table, association, join_type, options = {})
|
239
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
240
|
+
associations = association.is_a?(Array) ? association : [association]
|
241
|
+
|
242
|
+
alias_tracker = ActiveRecord::Associations::AliasTracker.create(
|
243
|
+
table.connection, table.name, {}
|
244
|
+
)
|
245
|
+
|
246
|
+
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
247
|
+
table, table.arel_table, associations, join_type
|
248
|
+
)
|
249
|
+
|
250
|
+
constraints = join_dependency.join_constraints([], alias_tracker, [])
|
251
|
+
|
252
|
+
constraints.map do |join|
|
253
|
+
apply_aliases(join, aliases)
|
254
|
+
|
255
|
+
right = if block_given?
|
256
|
+
yield join.left.name.to_sym, join.right
|
257
|
+
else
|
258
|
+
join.right
|
259
|
+
end
|
260
|
+
|
216
261
|
join_type.new(join.left, right)
|
217
262
|
end
|
218
263
|
end
|
219
264
|
|
265
|
+
def apply_aliases(node, aliases)
|
266
|
+
case node
|
267
|
+
when Arel::Nodes::Join
|
268
|
+
node.left = aliases[node.left.name] || node.left
|
269
|
+
apply_aliases(node.right, aliases)
|
270
|
+
when Arel::Attributes::Attribute
|
271
|
+
node.relation = aliases[node.relation.name] || node.relation
|
272
|
+
when Arel::Nodes::And
|
273
|
+
node.children.each { |child| apply_aliases(child, aliases) }
|
274
|
+
when Arel::Nodes::Unary
|
275
|
+
apply_aliases(node.value, aliases)
|
276
|
+
when Arel::Nodes::Binary
|
277
|
+
apply_aliases(node.left, aliases)
|
278
|
+
apply_aliases(node.right, aliases)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
220
282
|
private
|
221
283
|
|
222
284
|
def to_sql(node, table, binds)
|
@@ -224,10 +286,6 @@ module ArelHelpers
|
|
224
286
|
collect = visitor.accept(node, Arel::Collectors::Bind.new)
|
225
287
|
collect.substitute_binds(binds).join
|
226
288
|
end
|
227
|
-
|
228
|
-
def find_alias(name, aliases)
|
229
|
-
aliases.find { |a| a.table_name == name }
|
230
|
-
end
|
231
289
|
end
|
232
290
|
end
|
233
291
|
end
|
@@ -16,6 +16,21 @@ module ArelHelpers
|
|
16
16
|
|
17
17
|
def_delegators :@query, *TERMINAL_METHODS
|
18
18
|
|
19
|
+
def self.not_nil(name)
|
20
|
+
mod = Module.new do
|
21
|
+
define_method(name) do |*args, **kwargs|
|
22
|
+
if (value = super(*args, **kwargs))
|
23
|
+
value
|
24
|
+
else
|
25
|
+
reflect(query)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
prepend mod
|
31
|
+
name
|
32
|
+
end
|
33
|
+
|
19
34
|
def initialize(query)
|
20
35
|
@query = query
|
21
36
|
end
|
data/lib/arel-helpers/version.rb
CHANGED
data/spec/aliases_spec.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
require 'spec_helper'
|
4
2
|
|
5
3
|
describe ArelHelpers::Aliases do
|
6
|
-
describe
|
7
|
-
it
|
4
|
+
describe '#aliased_as' do
|
5
|
+
it 'yields an alias when passed a block' do
|
8
6
|
Post.aliased_as('foo') do |foo_alias|
|
9
7
|
expect(foo_alias).to be_a(Arel::Nodes::TableAlias)
|
10
8
|
expect(foo_alias.name).to eq('foo')
|
11
9
|
end
|
12
10
|
end
|
13
11
|
|
14
|
-
it
|
12
|
+
it 'is capable of yielding multiple aliases' do
|
15
13
|
Post.aliased_as('foo', 'bar') do |foo_alias, bar_alias|
|
16
14
|
expect(foo_alias).to be_a(Arel::Nodes::TableAlias)
|
17
15
|
expect(foo_alias.name).to eq('foo')
|
@@ -21,14 +19,14 @@ describe ArelHelpers::Aliases do
|
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
24
|
-
it
|
22
|
+
it 'returns an alias when not passed a block' do
|
25
23
|
aliases = Post.aliased_as('foo')
|
26
24
|
expect(aliases.size).to eq(1)
|
27
25
|
expect(aliases[0]).to be_a(Arel::Nodes::TableAlias)
|
28
26
|
expect(aliases[0].name).to eq('foo')
|
29
27
|
end
|
30
28
|
|
31
|
-
it
|
29
|
+
it 'is capable of returning multiple aliases' do
|
32
30
|
aliases = Post.aliased_as('foo', 'bar')
|
33
31
|
expect(aliases.size).to eq(2)
|
34
32
|
|
data/spec/arel_table_spec.rb
CHANGED
@@ -1,30 +1,28 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
require 'spec_helper'
|
4
2
|
|
5
3
|
describe ArelHelpers::ArelTable do
|
6
|
-
it
|
4
|
+
it 'should add the [] function to the model and allow attribute access' do
|
7
5
|
Post[:id].tap do |post_id|
|
8
|
-
post_id.
|
9
|
-
post_id.name.
|
10
|
-
post_id.relation.name.
|
6
|
+
expect(post_id).to be_a Arel::Attribute
|
7
|
+
expect(post_id.name.to_s).to eq 'id'
|
8
|
+
expect(post_id.relation.name).to eq 'posts'
|
11
9
|
end
|
12
10
|
end
|
13
11
|
|
14
|
-
it
|
12
|
+
it 'should not interfere with associations' do
|
15
13
|
post = Post.create(title: "I'm a little teapot")
|
16
|
-
post.comments[0].
|
14
|
+
expect(post.comments[0]).to be_nil
|
17
15
|
end
|
18
16
|
|
19
|
-
it
|
17
|
+
it 'should allow retrieving associated records' do
|
20
18
|
post = Post.create(title: "I'm a little teapot")
|
21
19
|
comment = post.comments.create
|
22
|
-
post.reload.comments[0].id.
|
20
|
+
expect(post.reload.comments[0].id).to eq comment.id
|
23
21
|
end
|
24
22
|
|
25
|
-
it
|
26
|
-
Post.all[0].
|
23
|
+
it 'does not interfere with ActiveRecord::Relation objects' do
|
24
|
+
expect(Post.all[0]).to be_nil
|
27
25
|
p = Post.create(title: 'foo')
|
28
|
-
Post.all[0].id.
|
26
|
+
expect(Post.all[0].id).to eq p.id
|
29
27
|
end
|
30
28
|
end
|
data/spec/env/models.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
class Post < ActiveRecord::Base
|
4
2
|
include ArelHelpers::ArelTable
|
5
3
|
include ArelHelpers::Aliases
|
@@ -44,12 +42,10 @@ end
|
|
44
42
|
|
45
43
|
class Location < ActiveRecord::Base
|
46
44
|
has_many :card_locations
|
47
|
-
has_many :community_tickets,
|
48
|
-
through: :card_locations, source: :card, source_type: 'CommunityTicket'
|
49
|
-
}
|
45
|
+
has_many :community_tickets, through: :card_locations, source: :card, source_type: 'CommunityTicket'
|
50
46
|
end
|
51
47
|
|
52
48
|
class CommunityTicket < ActiveRecord::Base
|
53
|
-
has_many :card_locations, as: :card
|
49
|
+
has_many :card_locations, as: :card
|
54
50
|
has_many :locations, through: :card_locations
|
55
51
|
end
|