arel-helpers 2.4.0 → 2.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +1 -12
- data/README.md +27 -1
- data/Rakefile +2 -2
- data/arel-helpers.gemspec +16 -14
- data/lib/arel-helpers.rb +2 -1
- data/lib/arel-helpers/aliases.rb +21 -0
- data/lib/arel-helpers/join_association.rb +161 -13
- data/lib/arel-helpers/query_builder.rb +16 -1
- data/lib/arel-helpers/version.rb +1 -1
- data/spec/aliases_spec.rb +40 -0
- data/spec/arel_table_spec.rb +11 -13
- data/spec/env/models.rb +7 -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 +2979 -0
- data/spec/join_association_spec.rb +111 -51
- data/spec/query_builder_spec.rb +36 -17
- data/spec/spec_helper.rb +10 -20
- metadata +101 -14
- data/History.txt +0 -43
- data/spec/env.rb +0 -44
- data/spec/env/migrations.rb +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d792fc6a4945a79243f3e4b9720c9f10ce21f5a044328f56f2b381045183589a
|
4
|
+
data.tar.gz: becca530d9ecfd5a25594ce0363cbde8d792d564358d2394a36d7040e6341384
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d825413e0dc2f3caff9ddcbc93a4eadbb1d8814196bc515fd13b3a759969db970a9fe2df911da86def2125d724d5c651e5a39eba2d9cf873d573c913b6a51f5
|
7
|
+
data.tar.gz: 70bea7795e9bcd75058dad5aaee877f6fb1d00e40f9e62b0db8b908d1a1f0656654fe67170a1024e1776b2a458ea11622fad399cda001ffd127c5f35f8197824
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -155,7 +155,7 @@ class PostQueryBuilder < ArelHelpers::QueryBuilder
|
|
155
155
|
def with_comments_by(usernames)
|
156
156
|
reflect(
|
157
157
|
query
|
158
|
-
.joins(:
|
158
|
+
.joins(comments: :author)
|
159
159
|
.where(author[:username].in(usernames))
|
160
160
|
)
|
161
161
|
end
|
@@ -187,6 +187,32 @@ 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
218
|
Requires ActiveRecord >= 3.1.0, < 6, tested against Ruby 2.2.4. Depends on SQLite for testing purposes.
|
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ require './lib/arel-helpers'
|
|
10
10
|
|
11
11
|
Bundler::GemHelper.install_tasks
|
12
12
|
|
13
|
-
task :
|
13
|
+
task default: :spec
|
14
14
|
|
15
15
|
desc 'Run specs'
|
16
16
|
RSpec::Core::RakeTask.new do |t|
|
@@ -21,7 +21,7 @@ task :console do
|
|
21
21
|
$:.push(File.dirname(__FILE__))
|
22
22
|
|
23
23
|
require 'spec/env'
|
24
|
-
require 'pry-
|
24
|
+
require 'pry-byebug'
|
25
25
|
|
26
26
|
ArelHelpers::Env.establish_connection
|
27
27
|
ArelHelpers::Env.reset
|
data/arel-helpers.gemspec
CHANGED
@@ -1,24 +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 =
|
10
|
-
|
11
|
-
s.description = s.summary =
|
7
|
+
s.authors = ['Cameron Dutro']
|
8
|
+
s.email = ['camertron@gmail.com']
|
9
|
+
s.homepage = 'https://github.com/camertron/arel-helpers'
|
10
|
+
s.license = 'MIT'
|
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
|
-
s.has_rdoc = true
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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'
|
21
23
|
|
22
24
|
s.require_path = 'lib'
|
23
|
-
s.files = Dir[
|
25
|
+
s.files = Dir['{lib,spec}/**/*', 'Gemfile', 'History.txt', 'README.md', 'Rakefile', 'arel-helpers.gemspec']
|
24
26
|
end
|
data/lib/arel-helpers.rb
CHANGED
@@ -17,8 +17,9 @@ rescue
|
|
17
17
|
end
|
18
18
|
|
19
19
|
module ArelHelpers
|
20
|
-
autoload :
|
20
|
+
autoload :Aliases, "arel-helpers/aliases"
|
21
21
|
autoload :ArelTable, "arel-helpers/arel_table"
|
22
|
+
autoload :JoinAssociation, "arel-helpers/join_association"
|
22
23
|
autoload :QueryBuilder, "arel-helpers/query_builder"
|
23
24
|
|
24
25
|
def self.join_association(*args, &block)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module ArelHelpers
|
4
|
+
|
5
|
+
module Aliases
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def aliased_as(*args)
|
10
|
+
aliases = args.map { |name| arel_table.alias(name) }
|
11
|
+
|
12
|
+
if block_given?
|
13
|
+
yield *aliases
|
14
|
+
else
|
15
|
+
aliases
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -17,21 +17,34 @@ module ArelHelpers
|
|
17
17
|
# For example, for HABTM associations, two join statements are required.
|
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
|
-
def join_association(table, association, join_type = Arel::Nodes::InnerJoin, &block)
|
21
|
-
if
|
22
|
-
|
23
|
-
elsif
|
24
|
-
|
25
|
-
elsif
|
26
|
-
|
20
|
+
def join_association(table, association, join_type = Arel::Nodes::InnerJoin, options = {}, &block)
|
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'
|
26
|
+
join_association_5_2_1(table, association, join_type, options, &block)
|
27
|
+
elsif version >= '5.2.0'
|
28
|
+
join_association_5_2(table, association, join_type, options, &block)
|
29
|
+
elsif version >= '5.0.0'
|
30
|
+
join_association_5_0(table, association, join_type, options, &block)
|
31
|
+
elsif version >= '4.2.0'
|
32
|
+
join_association_4_2(table, association, join_type, options, &block)
|
33
|
+
elsif version >= '4.1.0'
|
34
|
+
join_association_4_1(table, association, join_type, options, &block)
|
27
35
|
else
|
28
|
-
join_association_3_1(table, association, join_type, &block)
|
36
|
+
join_association_3_1(table, association, join_type, options, &block)
|
29
37
|
end
|
30
38
|
end
|
31
39
|
|
32
40
|
private
|
33
41
|
|
34
|
-
def
|
42
|
+
def version
|
43
|
+
ActiveRecord::VERSION::STRING
|
44
|
+
end
|
45
|
+
|
46
|
+
def join_association_3_1(table, association, join_type, options = {})
|
47
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
35
48
|
associations = association.is_a?(Array) ? association : [association]
|
36
49
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(table, associations, [])
|
37
50
|
manager = Arel::SelectManager.new(table)
|
@@ -42,8 +55,9 @@ module ArelHelpers
|
|
42
55
|
end
|
43
56
|
|
44
57
|
manager.join_sources.map do |assoc|
|
58
|
+
assoc.left.table_alias = aliases[assoc.left.name].name if aliases.key?(assoc.left.name)
|
59
|
+
|
45
60
|
if block_given?
|
46
|
-
# yield |assoc_name, join_conditions|
|
47
61
|
right = yield assoc.left.name.to_sym, assoc.right
|
48
62
|
assoc.class.new(assoc.left, right)
|
49
63
|
else
|
@@ -52,7 +66,8 @@ module ArelHelpers
|
|
52
66
|
end
|
53
67
|
end
|
54
68
|
|
55
|
-
def join_association_4_1(table, association, join_type)
|
69
|
+
def join_association_4_1(table, association, join_type, options = {})
|
70
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
56
71
|
associations = association.is_a?(Array) ? association : [association]
|
57
72
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(table, associations, [])
|
58
73
|
|
@@ -63,6 +78,8 @@ module ArelHelpers
|
|
63
78
|
constraint.right
|
64
79
|
end
|
65
80
|
|
81
|
+
constraint.left.table_alias = aliases[constraint.left.name].name if aliases.key?(constraint.left.name)
|
82
|
+
|
66
83
|
join_type.new(constraint.left, right)
|
67
84
|
end
|
68
85
|
end
|
@@ -72,7 +89,8 @@ module ArelHelpers
|
|
72
89
|
# join_association isn't able to add to the list of bind variables
|
73
90
|
# dynamically. To get around the problem, this method must return
|
74
91
|
# a string.
|
75
|
-
def join_association_4_2(table, association, join_type)
|
92
|
+
def join_association_4_2(table, association, join_type, options = {})
|
93
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
76
94
|
associations = association.is_a?(Array) ? association : [association]
|
77
95
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(table, associations, [])
|
78
96
|
|
@@ -90,6 +108,8 @@ module ArelHelpers
|
|
90
108
|
join.right
|
91
109
|
end
|
92
110
|
|
111
|
+
join.left.table_alias = aliases[join.left.name].name if aliases.key?(join.left.name)
|
112
|
+
|
93
113
|
join_type.new(join.left, right)
|
94
114
|
end
|
95
115
|
end
|
@@ -101,7 +121,8 @@ module ArelHelpers
|
|
101
121
|
join_strings.join(' ')
|
102
122
|
end
|
103
123
|
|
104
|
-
def join_association_5_0(table, association, join_type)
|
124
|
+
def join_association_5_0(table, association, join_type, options = {})
|
125
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
105
126
|
associations = association.is_a?(Array) ? association : [association]
|
106
127
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(table, associations, [])
|
107
128
|
|
@@ -120,6 +141,8 @@ module ArelHelpers
|
|
120
141
|
join.right
|
121
142
|
end
|
122
143
|
|
144
|
+
join.left.table_alias = aliases[join.left.name].name if aliases.key?(join.left.name)
|
145
|
+
|
123
146
|
join_type.new(join.left, right)
|
124
147
|
end
|
125
148
|
end
|
@@ -131,6 +154,131 @@ module ArelHelpers
|
|
131
154
|
join_strings.join(' ')
|
132
155
|
end
|
133
156
|
|
157
|
+
def join_association_5_2(table, association, join_type, options = {})
|
158
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
159
|
+
associations = association.is_a?(Array) ? association : [association]
|
160
|
+
|
161
|
+
alias_tracker = ActiveRecord::Associations::AliasTracker.create(
|
162
|
+
table.connection, table.name, {}
|
163
|
+
)
|
164
|
+
|
165
|
+
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
166
|
+
table, table.arel_table, associations, alias_tracker
|
167
|
+
)
|
168
|
+
|
169
|
+
constraints = join_dependency.join_constraints([], join_type)
|
170
|
+
|
171
|
+
constraints.map do |join|
|
172
|
+
right = if block_given?
|
173
|
+
yield join.left.name.to_sym, join.right
|
174
|
+
else
|
175
|
+
join.right
|
176
|
+
end
|
177
|
+
|
178
|
+
join.left.table_alias = aliases[join.left.name].name if aliases.key?(join.left.name)
|
179
|
+
|
180
|
+
join_type.new(join.left, right)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def join_association_5_2_1(table, association, join_type, options = {})
|
185
|
+
aliases = options.fetch(:aliases, []).index_by(&:table_name)
|
186
|
+
associations = association.is_a?(Array) ? association : [association]
|
187
|
+
|
188
|
+
alias_tracker = ActiveRecord::Associations::AliasTracker.create(
|
189
|
+
table.connection, table.name, {}
|
190
|
+
)
|
191
|
+
|
192
|
+
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
193
|
+
table, table.arel_table, associations
|
194
|
+
)
|
195
|
+
|
196
|
+
constraints = join_dependency.join_constraints([], join_type, alias_tracker)
|
197
|
+
|
198
|
+
constraints.map do |join|
|
199
|
+
right = if block_given?
|
200
|
+
yield join.left.name.to_sym, join.right
|
201
|
+
else
|
202
|
+
join.right
|
203
|
+
end
|
204
|
+
|
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
|
230
|
+
end
|
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
|
+
|
261
|
+
join_type.new(join.left, right)
|
262
|
+
end
|
263
|
+
end
|
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
|
+
|
134
282
|
private
|
135
283
|
|
136
284
|
def to_sql(node, table, binds)
|
@@ -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|
|
22
|
+
if (value = super(*args))
|
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
|
@@ -23,7 +38,7 @@ module ArelHelpers
|
|
23
38
|
protected
|
24
39
|
|
25
40
|
def reflect(query)
|
26
|
-
|
41
|
+
dup.tap { |obj| obj.instance_variable_set('@query'.freeze, query) }
|
27
42
|
end
|
28
43
|
end
|
29
44
|
end
|
data/lib/arel-helpers/version.rb
CHANGED