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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6356cdb2e00758c2e17276118d916f727a1be308
4
- data.tar.gz: 26faaf1834fd66939b376ef0caa88f7e85d6bc41
2
+ SHA256:
3
+ metadata.gz: d792fc6a4945a79243f3e4b9720c9f10ce21f5a044328f56f2b381045183589a
4
+ data.tar.gz: becca530d9ecfd5a25594ce0363cbde8d792d564358d2394a36d7040e6341384
5
5
  SHA512:
6
- metadata.gz: e07f4c676161cd241f861b48aef16411f262f09fc53d9773432e185804e062c41d117d196f553b2fb3fff834c42ec7fbd3e081ad42ed741a6ced87f66d7c1a73
7
- data.tar.gz: 9a72da308ac57e7df7dab0fce3c2909d6478f8c96170ede5c98fcf940f51f415c529838150dca14fd83ced259846c84601d312fb406b59a1545d120c43fa46c1
6
+ metadata.gz: 2d825413e0dc2f3caff9ddcbc93a4eadbb1d8814196bc515fd13b3a759969db970a9fe2df911da86def2125d724d5c651e5a39eba2d9cf873d573c913b6a51f5
7
+ data.tar.gz: 70bea7795e9bcd75058dad5aaee877f6fb1d00e40f9e62b0db8b908d1a1f0656654fe67170a1024e1776b2a458ea11622fad399cda001ffd127c5f35f8197824
data/Gemfile CHANGED
@@ -1,14 +1,3 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- group :development, :test do
6
- gem 'pry-nav'
7
- gem 'rake'
8
- end
9
-
10
- group :test do
11
- gem 'rspec', '~> 2.11.0'
12
- gem 'rr', '~> 1.0.4'
13
- gem 'sqlite3'
14
- end
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(:comments => :author)
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 :default => :spec
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-nav'
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
- $:.unshift File.join(File.dirname(__FILE__), 'lib')
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 = "arel-helpers"
5
+ s.name = 'arel-helpers'
6
6
  s.version = ::ArelHelpers::VERSION
7
- s.authors = ["Cameron Dutro"]
8
- s.email = ["camertron@gmail.com"]
9
- s.homepage = "http://github.com/camertron"
10
-
11
- s.description = s.summary = "Useful tools to help construct database queries with ActiveRecord and Arel."
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
- if ENV["AR"]
17
- s.add_dependency 'activerecord', ENV["AR"]
18
- else
19
- s.add_dependency 'activerecord', '>= 3.1.0', '< 6'
20
- end
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["{lib,spec}/**/*", "Gemfile", "History.txt", "README.md", "Rakefile", "arel-helpers.gemspec"]
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 :JoinAssociation, "arel-helpers/join_association"
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 ActiveRecord::VERSION::STRING >= '5.0.0'
22
- join_association_5_0(table, association, join_type, &block)
23
- elsif ActiveRecord::VERSION::STRING >= '4.2.0'
24
- join_association_4_2(table, association, join_type, &block)
25
- elsif ActiveRecord::VERSION::STRING >= '4.1.0'
26
- join_association_4_1(table, association, join_type, &block)
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 join_association_3_1(table, association, join_type)
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
- self.class.new(query)
41
+ dup.tap { |obj| obj.instance_variable_set('@query'.freeze, query) }
27
42
  end
28
43
  end
29
44
  end
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module ArelHelpers
4
- VERSION = '2.4.0'
4
+ VERSION = '2.12.0'
5
5
  end