arel-helpers 2.4.0 → 2.12.0
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 +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