baby_squeel 1.3.1 → 1.4.4

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
2
  SHA256:
3
- metadata.gz: a31dea90feb497d7b2cc1f01a18a9ea8a6c7ab3819f003a660b44a2ce409f4b6
4
- data.tar.gz: ae9a5da834fe1e917085c4d370543dd89de9ef5b44cc83c384c9268516c933ff
3
+ metadata.gz: 54dbc98299ab8f9909d8c312e9663cc615543ea6421b81f2aab6efdd2bd9fe59
4
+ data.tar.gz: 97cc39dced57e0bd6bf16c854859f47902a2d6550e71c4120643fb01d0de9529
5
5
  SHA512:
6
- metadata.gz: 5883394797bdeb50a88fef7b3b5032c7cfcf7a3dd80c7de197aa763aadf2b019e5aa0e5a8d66967268cacc5b52e3dfc3aa0de02eb235939492c3ee41a50be078
7
- data.tar.gz: ce1de58a03cb4a08e789e9c6ab9feb12333f45c477d3780b4eecb9d7acf9bb18c920fd632b5d74b059af95827cb5463bc82ee2fe8eee634ac47777a7015f1493
6
+ metadata.gz: 8f5e68cf4ac0e85d2dc8fce1741f2d64c2bd5b5ecc08c335d71ad3fae335fb3b580f5c3aa2c5f98053ec445d9a7fbc1d3ddec6c7218c99bcb9869a6767fa68c8
7
+ data.tar.gz: ca66ea54876dfb670177ccea3be1808c90b4d1affea3b7bc1cb5c515e6e8208a8b55fb9fcd06202c6411ea102a358ceb0aa7d0468f82ee7c857045fbc0c5e946
data/CHANGELOG.md CHANGED
@@ -1,134 +1,224 @@
1
1
  ## [Unreleased]
2
2
 
3
- Nothing to see here.
3
+ ## [1.4.4] - 2022-02-07
4
+
5
+ ### Fixed
6
+
7
+ - Nested merge-joins query causes NoMethodError with ActiveRecord 6.1.4.4 (#119)
8
+
9
+ ## [1.4.3] - 2022-02-04
10
+
11
+ ### Fixed
12
+
13
+ - ActiveRecord::Relation#left_joins performs INNER JOIN on Active Record 6.1 (#118)
14
+
15
+ ## [1.4.2] - 2022-01-24
16
+
17
+ ### Fixed
18
+
19
+ - Added support for activerecord 7.0 (#116)
20
+ - Added support for activerecord 6.1 (#116)
21
+ - Added support for activerecord 6.0 (#116)
22
+
23
+ ## [1.4.1] - 2021-06-17
24
+
25
+ ### Fixed
26
+
27
+ - Fixed a bug related to checking the Active Record version.
28
+
29
+ ## [1.4.0] - 2021-06-17
30
+
31
+ ### Fixed
32
+
33
+ - Fix table alias when joining a polymorphic table twice (#108)
34
+ - Removed internal class `BabySqueel::Pluck`. You can still use `plucking`. For example, `Post.joining { author }.plucking { author.name }`
35
+ - Removed old code from Active Record < 5.2
36
+ - Removed dependency `join_dependency`
37
+
38
+ ## [1.4.0.beta1] - 2021-04-21
39
+
40
+ ### Fixed
41
+
42
+ - Add Support for activerecord '>= 5.2.3'
43
+ - Drop Support for Active Record versions that have reached EOL (activerecord < 5.2)
44
+ - Use polyamorous from ransack '~> 2.3'
4
45
 
5
46
  ## [1.3.1] - 2018-05-15
6
- ## Fixed
47
+
48
+ ### Fixed
49
+
7
50
  - Upgraded `join_dependency` requirement, which fixes [issue #1](https://github.com/rzane/join_dependency/issues/1).
8
51
 
9
52
  ## [1.3.0] - 2018-05-04
10
- ## Added
53
+
54
+ ### Added
55
+
11
56
  - The ability to use `plucking` with an array of nodes. For example, `User.plucking { [id, name] }`.
12
57
 
13
58
  ## [1.2.1] - 2018-04-25
14
- ## Fixed
59
+
60
+ ### Fixed
61
+
15
62
  - Added support for Active Record 5.2
16
63
 
17
64
  ## [1.2.0] - 2017-10-20
65
+
18
66
  ### Added
67
+
19
68
  - `reordering`, which is just a BabySqueel version of Active Record's `reorder`.
20
69
  - `on` expressions can now be given a block that will yield the current node (#77).
21
70
 
22
71
  ## [1.1.5] - 2017-05-26
72
+
23
73
  ### Fixed
74
+
24
75
  - Returning an empty hash from a `where.has {}` block would generate invalid SQL (#69).
25
76
 
26
77
  ## [1.1.4] - 2017-04-13
78
+
27
79
  ### Fixed
80
+
28
81
  - Nodes::Attribute#in and #not_in generate valid SQL when given ActiveRecord::NullRelations.
29
82
 
30
83
  ## [1.1.3] - 2017-03-31
84
+
31
85
  ### Fixed
86
+
32
87
  - Nodes::Attribute#in was not returning BabySqueel node. As a result, you couldn't chain on it. This fixes #61.
33
88
 
34
89
  ## [1.1.2] - 2017-03-21
90
+
35
91
  ### Fixed
92
+
36
93
  - Check if a reflection has a parent reflection before comparing them. This fixes #56.
37
94
 
38
95
  ### Refactored
96
+
39
97
  - The logic encapsulated in `#method_missing` and `#respond_to_missing?` was difficult to follow, because it was falling back to `super`, sometimes going up the inheritance tree multiple levels. The addition of `BabySqueel::Resolver` now handles this a little more gracefully.
40
98
 
41
99
  ## [1.1.1] - 2017-02-14
100
+
42
101
  ### Fixed
102
+
43
103
  - There is a bug in Active Record where the `AliasTracker` initializes `Arel::Table`s use the wrong `type_caster`. To address this, BabySqueel must re-initialize the `Arel::Table` with the correct `type_caster` (#54).
44
104
 
45
105
  ## [1.1.0] - 2017-02-10
106
+
46
107
  > This version drops support for Active Record 4.1. If you're stil on 4.1, you should seriously consider upgrading to at least 4.2.
47
108
 
48
109
  ### Added
110
+
49
111
  - DSLs for ActiveRecord::Relation::Calculations. You can now use `plucking`, `counting`, `summing`, `averaging`, `minimizing`, and `maximizing`.
50
112
 
51
113
  ## [1.0.3] - 2017-02-09
114
+
52
115
  ### Added
116
+
53
117
  - Support for `pluck`.
54
118
  - Support for `not_in`.
55
119
 
56
120
  ## [1.0.2] - 2017-02-07
121
+
57
122
  ### Added
123
+
58
124
  - `BabySqueel::Association` now has `#==` and `#!=`. This is only supported for Rails 5+. Example: `Post.where { author: Author.last }`.
59
125
 
60
126
  ### Fixed
127
+
61
128
  - Incorrect alias detection caused by not tracking the full path to a join (#37).
62
129
 
63
130
  ## [1.0.1] - 2016-11-07
131
+
64
132
  ### Added
65
- - Add DSL#_ for wrapping expressions in Arel::Node::Grouping. Thanks to [@odedniv].
133
+
134
+ - Add DSL#\_ for wrapping expressions in Arel::Node::Grouping. Thanks to [@odedniv].
66
135
 
67
136
  ### Fixed
137
+
68
138
  - Use strings for attribute names like Rails does. Symbols were preventing things like `unscope` from working. Thanks to [@chewi].
69
139
  - `where.has {}` will now accept `nil`.
70
140
  - Arel::Nodes::Function did not previously include Arel::Math, so now you can do math operations on the result of SQL functions.
71
141
  - Arel::Nodes::Binary did not previously include Arel::AliasPredication. Binary nodes can now be aliased using `as`.
72
142
 
73
143
  ## [1.0.0] - 2016-09-09
144
+
74
145
  ### Added
75
- - Polyamorous. Unfortunately, this *does* monkey-patch Active Record internals, but there just isn't any other reliable way to generate outer joins. Baby Squeel, itself, will still keep monkey patching to an absolute minimum.
146
+
147
+ - Polyamorous. Unfortunately, this _does_ monkey-patch Active Record internals, but there just isn't any other reliable way to generate outer joins. Baby Squeel, itself, will still keep monkey patching to an absolute minimum.
76
148
  - Within DSL blocks, you can use `exists` and `not_exists` with Active Record relations. For example: `Post.where.has { exists Post.where(title: 'Fun') }`.`
77
149
  - Support for polymorphic associations.
78
150
 
79
151
  ### Deprecations
152
+
80
153
  - Removed support for Active Record 4.0.x
81
154
 
82
155
  ### Changed
156
+
83
157
  - BabySqueel::JoinDependency is no longer a class responsible for creating Arel joins. It is now a namespace for utilities used when working with the ActiveRecord::Association::JoinDependency class.
84
158
  - BabySqueel::Nodes::Generic is now BabySqueel::Nodes::Node.
85
159
  - Arel nodes are only extended with the behaviors they need. Previously, all Arel nodes were being extended with `Arel::AliasPredication`, `Arel::OrderPredications`, and `Arel::Math`.
86
160
 
87
161
  ### Fixed
162
+
88
163
  - Fixed deprecation warnings on Active Record 5 when initializing an Arel::Table without a type caster.
89
164
  - No more duplicate joins. Previously, Baby Squeel did a very poor job of ensuring that you didn't join an association twice.
90
- - Alias detection should now *actually* work. The previous implementation was naive.
165
+ - Alias detection should now _actually_ work. The previous implementation was naive.
91
166
 
92
167
  ## [0.3.1] - 2016-08-02
168
+
93
169
  ### Added
170
+
94
171
  - Ported backticks and #my from Squeel
95
172
 
96
173
  ### Changed
174
+
97
175
  - DSL#sql now returns a node wrapped in a BabySqueel proxy.
98
176
 
99
177
  ## [0.3.0] - 2016-06-26
178
+
100
179
  ### Added
180
+
101
181
  - Added Squeel compatibility mode that allows `select`, `order`, `joins`, `group`, `where`, and `having` to accept DSL blocks.
102
182
  - Added the ability to query tables that aren't backed by Active Record models.
103
183
  - Added `BabySqueel::[]`, which provides a `BabySqueel::Relation` for models, or a `BabySqueel::Table` for symbols/strings.
104
184
 
105
185
  ### Changed
186
+
106
187
  - Renamed `BabySqueel::Association::AliasingError` to `BabySqueel::AssociationAliasingError`.
107
188
 
108
189
  ## [0.2.2] - 2016-03-30
190
+
109
191
  ### Added
192
+
110
193
  - Support for `group` (`grouping`) and `having` (`when_having`).
111
194
  - Support for sifters.
112
195
  - Added `quoted` and `sql` helpers for quoting strings and SQL literals.
113
196
  - More descriptive error messages when a column or association is not found.
114
197
 
115
198
  ### Fixed
199
+
116
200
  - `Arel::Nodes::Grouping` does not include `Arel::Math`, so operations like `(id + 5) + 3` would fail unexpectedly.
117
201
  - Fix missing bind values When joining through associations with default scope.
118
202
  - Removed `ActiveRecord::VERSION` specific handling of the `WhereChain`.
119
203
 
120
204
  ## [0.2.1] - 2016-03-27
205
+
121
206
  ### Added
207
+
122
208
  - Support for subqueries.
123
209
 
124
210
  ### Fixed
211
+
125
212
  - Some Arel nodes did not have access to `as` expressions.
126
213
 
127
214
  ## [0.2.0] - 2016-03-25
215
+
128
216
  ### Added
217
+
129
218
  - References to aliased joins in a `select`, `where`, or `order` expression now use the aliased table name.
130
219
 
131
220
  ### Changed
221
+
132
222
  - Rely on `ActiveRecord::Relation#join_sources` for the implicit construction of join nodes, rather than using the `ActiveRecord::Associations::JoinDependency` directly.
133
223
 
134
224
  ### Fixed
@@ -136,10 +226,18 @@ Nothing to see here.
136
226
  - Associations referencing the same table weren't being aliased.
137
227
 
138
228
  ## [0.1.0] - 2016-03-16
229
+
139
230
  ### Added
231
+
140
232
  - Initial support for selects, orders, wheres, and joins.
141
233
 
142
- [Unreleased]: https://github.com/rzane/baby_squeel/compare/v1.3.1...HEAD
234
+ [unreleased]: https://github.com/rzane/baby_squeel/compare/v1.4.4...HEAD
235
+ [1.4.4]: https://github.com/rzane/baby_squeel/compare/v1.4.3...v1.4.4
236
+ [1.4.3]: https://github.com/rzane/baby_squeel/compare/v1.4.2...v1.4.3
237
+ [1.4.2]: https://github.com/rzane/baby_squeel/compare/v1.4.1...v1.4.2
238
+ [1.4.1]: https://github.com/rzane/baby_squeel/compare/v1.4.0...v1.4.1
239
+ [1.4.0]: https://github.com/rzane/baby_squeel/compare/v1.4.0.beta1...v1.4.0
240
+ [1.4.0.beta1]: https://github.com/rzane/baby_squeel/compare/v1.3.1...v1.4.0.beta1
143
241
  [1.3.1]: https://github.com/rzane/baby_squeel/compare/v1.3.0...v1.3.1
144
242
  [1.3.0]: https://github.com/rzane/baby_squeel/compare/v1.2.1...v1.3.0
145
243
  [1.2.1]: https://github.com/rzane/baby_squeel/compare/v1.2.0...v1.2.1
@@ -159,6 +257,5 @@ Nothing to see here.
159
257
  [0.2.2]: https://github.com/rzane/baby_squeel/compare/v0.2.1...v0.2.2
160
258
  [0.2.1]: https://github.com/rzane/baby_squeel/compare/v0.2.0...v0.2.1
161
259
  [0.2.0]: https://github.com/rzane/baby_squeel/compare/v0.1.0...v0.2.0
162
-
163
260
  [@chewi]: https://github.com/chewi
164
261
  [@odedniv]: https://github.com/odedniv
data/ISSUE_TEMPLATE.md CHANGED
@@ -11,7 +11,7 @@ require 'minitest/autorun'
11
11
 
12
12
  gemfile true do
13
13
  source 'https://rubygems.org'
14
- gem 'activerecord', '~> 5.0.0' # which Active Record version?
14
+ gem 'activerecord', '~> 5.2.0' # which Active Record version?
15
15
  gem 'sqlite3'
16
16
  gem 'baby_squeel', github: 'rzane/baby_squeel'
17
17
  end
data/README.md CHANGED
@@ -1,10 +1,7 @@
1
- # BabySqueel
1
+ # BabySqueel 🐷
2
2
 
3
- [![Build Status](https://travis-ci.org/rzane/baby_squeel.svg?branch=master)](https://travis-ci.org/rzane/baby_squeel)
4
- [![Code Climate](https://codeclimate.com/github/rzane/baby_squeel/badges/gpa.svg)](https://codeclimate.com/github/rzane/baby_squeel)
5
- [![Coverage Status](https://coveralls.io/repos/github/rzane/baby_squeel/badge.svg?branch=master)](https://coveralls.io/github/rzane/baby_squeel?branch=master)
6
-
7
- <img align="right" src="http://static.thefrisky.com/uploads/2010/07/01/pig_in_boots_070110_m.jpg" alt="biddy piggy">
3
+ ![Build](https://github.com/rzane/baby_squeel/workflows/Build/badge.svg)
4
+ ![Version](https://img.shields.io/gem/v/baby_squeel)
8
5
 
9
6
  Have you ever used the [Squeel](https://github.com/activerecord-hackery/squeel) gem? It's a really nice way to build complex queries. However, Squeel monkeypatches Active Record internals, because it was aimed at enhancing the existing API with the aim of inclusion into Rails. However, that inclusion never happened, and it left Squeel susceptible to breakage from arbitrary changes in Active Record, eventually burning out the maintainer.
10
7
 
@@ -219,6 +216,21 @@ Post.joins(:author).where.has {
219
216
  # )
220
217
  ```
221
218
 
219
+ ##### Exists
220
+
221
+ ```ruby
222
+ Post.where.has {
223
+ exists Post.where.has { author_id == 1 }
224
+ }
225
+ # SELECT "posts".* FROM "posts"
226
+ # WHERE (
227
+ # EXISTS(
228
+ # SELECT "posts".* FROM "posts"
229
+ # WHERE "posts"."author_id" = 1
230
+ # )
231
+ # )
232
+ ```
233
+
222
234
  ##### Custom SQL Operators
223
235
 
224
236
  ```ruby
@@ -240,6 +252,26 @@ Post.joining {
240
252
  }
241
253
  ```
242
254
 
255
+ ##### Polymorphism
256
+
257
+ Given this polymorphism:
258
+
259
+ ```ruby
260
+ # app/models/picture.rb
261
+ belongs_to :imageable, polymorphic: true
262
+
263
+ # app/models/post.rb
264
+ has_many :pictures, as: :imageable
265
+ ```
266
+
267
+ The query might look like this:
268
+
269
+ ```ruby
270
+ Picture.
271
+ joining { imageable.of(Post) }.
272
+ selecting { imageable.of(Post).id }
273
+ ```
274
+
243
275
  ##### Helpers
244
276
 
245
277
  ```ruby
@@ -283,7 +315,7 @@ Post.joins(:author).where.has {
283
315
  The following methods give you access to BabySqueel's DSL:
284
316
 
285
317
  | BabySqueel | Active Record Equivalent |
286
- |---------------|--------------------------|
318
+ | ------------- | ------------------------ |
287
319
  | `selecting` | `select` |
288
320
  | `ordering` | `order` |
289
321
  | `joining` | `joins` |
@@ -297,7 +329,7 @@ Check out the [migration guide](https://github.com/rzane/baby_squeel/wiki/Migrat
297
329
 
298
330
  ## Development
299
331
 
300
- 1. Pick an Active Record version to develop against, then export it: `export AR=4.2.6`.
332
+ 1. Pick an Active Record version to develop against, then export it: `export AR=6.1.4`.
301
333
  2. Run `bin/setup` to install dependencies.
302
334
  3. Run `rake` to run the specs.
303
335
 
data/baby_squeel.gemspec CHANGED
@@ -19,12 +19,11 @@ Gem::Specification.new do |spec|
19
19
 
20
20
  spec.files = Dir.glob('{lib/**/*,*.{md,txt,gemspec}}')
21
21
 
22
- spec.add_dependency 'activerecord', '>= 4.2.0'
23
- spec.add_dependency 'polyamorous', '~> 1.3'
24
- spec.add_dependency 'join_dependency', '~> 0.1.2'
22
+ spec.add_dependency 'activerecord', '>= 5.2', '< 7.1'
23
+ spec.add_dependency 'ransack', '~> 2.3'
25
24
 
26
- spec.add_development_dependency 'bundler', '~> 1.11'
27
- spec.add_development_dependency 'rake', '~> 10.0'
28
- spec.add_development_dependency 'rspec', '~> 3.4.0'
25
+ spec.add_development_dependency 'bundler', '~> 2'
26
+ spec.add_development_dependency 'rake', '~> 13.0'
27
+ spec.add_development_dependency 'rspec', '~> 3.10'
29
28
  spec.add_development_dependency 'sqlite3'
30
29
  end
@@ -1,12 +1,10 @@
1
1
  require 'baby_squeel/calculation'
2
- require 'baby_squeel/pluck'
3
2
 
4
3
  module BabySqueel
5
4
  module ActiveRecord
6
5
  module Calculations
7
6
  def plucking(&block)
8
7
  nodes = Array.wrap(DSL.evaluate(self, &block))
9
- nodes = nodes.map { |node| Pluck.decorate(node) }
10
8
  pluck(*nodes)
11
9
  end
12
10
 
@@ -40,17 +38,6 @@ module BabySqueel
40
38
  super
41
39
  end
42
40
  end
43
-
44
- if ::ActiveRecord::VERSION::MAJOR < 5
45
- # @override
46
- def type_for(field)
47
- if field.kind_of? Calculation
48
- field
49
- else
50
- super
51
- end
52
- end
53
- end
54
41
  end
55
42
  end
56
43
  end
@@ -1,9 +1,26 @@
1
1
  require 'baby_squeel/dsl'
2
2
  require 'baby_squeel/join_dependency'
3
+ require 'baby_squeel/active_record/version_helper'
3
4
 
4
5
  module BabySqueel
5
6
  module ActiveRecord
6
7
  module QueryMethods
8
+ # This class allows BabySqueel to slip custom
9
+ # joins_values into Active Record's JoinDependency
10
+ module Injector6_1
11
+ def each(&block)
12
+ super do |join|
13
+ if join.is_a?(BabySqueel::Join)
14
+ result = block.binding.local_variables.include?(:result) && block.binding.local_variable_get(:result)
15
+ result << join if result
16
+ join
17
+ else
18
+ block.call(join)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
7
24
  # Constructs Arel for ActiveRecord::QueryMethods#joins using the DSL.
8
25
  def joining(&block)
9
26
  joins DSL.evaluate(self, &block)
@@ -34,19 +51,41 @@ module BabySqueel
34
51
  having DSL.evaluate(self, &block)
35
52
  end
36
53
 
37
- private
54
+ if BabySqueel::ActiveRecord::VersionHelper.at_least_6_1?
55
+ def construct_join_dependency(associations, join_type)
56
+ result = super(associations, join_type)
57
+ if associations.any? { |assoc| assoc.is_a?(BabySqueel::Join) }
58
+ result.extend(BabySqueel::JoinDependency::Injector6_1)
59
+ end
60
+ result
61
+ end
62
+
63
+ private
64
+
65
+ # https://github.com/rails/rails/commit/c0c53ee9d28134757cf1418521cb97c4a135f140
66
+ def select_association_list(*args)
67
+ args[0].extend(BabySqueel::ActiveRecord::QueryMethods::Injector6_1)
68
+ super *args
69
+ end
70
+ elsif BabySqueel::ActiveRecord::VersionHelper.at_least_6_0?
71
+ private
38
72
 
39
- # This is a monkey patch, and I'm not happy about it.
40
- # Active Record will call `group_by` on the `joins`. The
41
- # Injector has a custom `group_by` method that handles
42
- # BabySqueel::Join nodes.
43
- if ::ActiveRecord::VERSION::MAJOR >= 5 && ::ActiveRecord::VERSION::MINOR >= 2
44
- def build_joins(manager, joins, aliases)
45
- super manager, BabySqueel::JoinDependency::Injector.new(joins), aliases
73
+ # Active Record will call `each` on the `joins`. The
74
+ # Injector has a custom `each` method that handles
75
+ # BabySqueel::Join nodes.
76
+ def build_joins(*args)
77
+ args[1] = BabySqueel::JoinDependency::Injector6_0.new(args.second)
78
+ super(*args)
46
79
  end
47
80
  else
48
- def build_joins(manager, joins)
49
- super manager, BabySqueel::JoinDependency::Injector.new(joins)
81
+ private
82
+
83
+ # Active Record will call `group_by` on the `joins`. The
84
+ # Injector has a custom `group_by` method that handles
85
+ # BabySqueel::Join nodes.
86
+ def build_joins(*args)
87
+ args[1] = BabySqueel::JoinDependency::Injector5_2.new(args.second)
88
+ super(*args)
50
89
  end
51
90
  end
52
91
  end
@@ -0,0 +1,21 @@
1
+ require 'baby_squeel/dsl'
2
+
3
+ module BabySqueel
4
+ module ActiveRecord
5
+ class VersionHelper
6
+ def self.at_least_6_1?
7
+ ::ActiveRecord::VERSION::MAJOR > 6 ||
8
+ ::ActiveRecord::VERSION::MAJOR == 6 && ::ActiveRecord::VERSION::MINOR >= 1
9
+ end
10
+
11
+ def self.at_least_6_0?
12
+ ::ActiveRecord::VERSION::MAJOR >= 6
13
+ end
14
+
15
+ def self.at_least_5_2_3?
16
+ at_least_6_0? ||
17
+ ::ActiveRecord::VERSION::MAJOR >= 5 && ::ActiveRecord::VERSION::MINOR >= 2 && ::ActiveRecord::VERSION::TINY >= 3
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,4 +1,5 @@
1
1
  require 'baby_squeel/relation'
2
+ require 'baby_squeel/active_record/version_helper'
2
3
 
3
4
  module BabySqueel
4
5
  class Association < Relation
@@ -96,19 +97,18 @@ module BabySqueel
96
97
 
97
98
  private
98
99
 
99
- if ActiveRecord::VERSION::MAJOR >= 5
100
- def build_where_clause(other)
101
- if valid_where_clause?(other)
102
- relation = @parent._scope.all
100
+ def build_where_clause(other)
101
+ if valid_where_clause?(other)
102
+ relation = @parent._scope.all
103
+
104
+ if BabySqueel::ActiveRecord::VersionHelper.at_least_6_1?
105
+ relation.send(:build_where_clause, { _reflection.name => other }, [])
106
+ else
103
107
  factory = relation.send(:where_clause_factory)
104
108
  factory.build({ _reflection.name => other }, [])
105
- else
106
- raise AssociationComparisonError.new(_reflection.name, other)
107
109
  end
108
- end
109
- else
110
- def build_where_clause(_)
111
- raise AssociationComparisonNotSupportedError.new(_reflection.name)
110
+ else
111
+ raise AssociationComparisonError.new(_reflection.name, other)
112
112
  end
113
113
  end
114
114
 
@@ -6,12 +6,6 @@ module BabySqueel
6
6
  @node = node
7
7
  end
8
8
 
9
- # This is only used in 4.2. We're just pretending to be
10
- # a database column to fake the casting here.
11
- def type_cast_from_database(value)
12
- value
13
- end
14
-
15
9
  # In Active Record 5, we don't *need* this class to make
16
10
  # calculations work. They happily accept arel. However,
17
11
  # when grouping with a calculation, there's a really,
@@ -21,15 +15,19 @@ module BabySqueel
21
15
  # caching because the alias would have a unique name every
22
16
  # time.
23
17
  def to_s
24
- names = node.map do |child|
25
- if child.kind_of?(String) || child.kind_of?(Symbol)
26
- child.to_s
27
- elsif child.respond_to?(:name)
28
- child.name.to_s
18
+ if node.respond_to?(:map)
19
+ names = node.map do |child|
20
+ if child.kind_of?(String) || child.kind_of?(Symbol)
21
+ child.to_s
22
+ elsif child.respond_to?(:name)
23
+ child.name.to_s
24
+ end
29
25
  end
26
+ names.compact.uniq.join('_')
27
+ else
28
+ # fix for https://github.com/rails/rails/commit/fc38ff6e4417295c870f419f7c164ab5a7dbc4a5
29
+ node.to_sql.split('"').map { |v| v.tr('^A-Za-z0-9_', '').presence }.compact.uniq.join('_')
30
30
  end
31
-
32
- names.compact.uniq.join('_')
33
31
  end
34
32
  end
35
33
  end
@@ -62,14 +62,4 @@ module BabySqueel
62
62
  super "You can't compare association '#{name}' to #{other}."
63
63
  end
64
64
  end
65
-
66
- class AssociationComparisonNotSupportedError < StandardError # :nodoc:
67
- MESSAGE =
68
- "Querying association '%{name}' with '==' and '!=' " \
69
- "is only supported for ActiveRecord >=5."
70
-
71
- def initialize(name)
72
- super format(MESSAGE, name: name)
73
- end
74
- end
75
65
  end
@@ -1,10 +1,10 @@
1
- require 'join_dependency'
1
+ require 'baby_squeel/active_record/version_helper'
2
2
 
3
3
  module BabySqueel
4
4
  module JoinDependency
5
5
  # This class allows BabySqueel to slip custom
6
6
  # joins_values into Active Record's JoinDependency
7
- class Injector < Array # :nodoc:
7
+ class Injector5_2 < Array # :nodoc:
8
8
  # Active Record will call group_by on this object
9
9
  # in ActiveRecord::QueryMethods#build_joins. This
10
10
  # allows BabySqueel::Joins to be treated
@@ -22,56 +22,146 @@ module BabySqueel
22
22
  end
23
23
  end
24
24
 
25
+ # This class allows BabySqueel to slip custom
26
+ # joins_values into Active Record's JoinDependency
27
+ class Injector6_0 < Array # :nodoc:
28
+ # https://github.com/rails/rails/pull/36805/files
29
+ # This commit changed group_by to each
30
+ def each(&block)
31
+ super do |join|
32
+ if block.binding.local_variables.include?(:buckets)
33
+ buckets = block.binding.local_variable_get(:buckets)
34
+
35
+ case join
36
+ when BabySqueel::Join
37
+ buckets[:association_join] << join
38
+ else
39
+ block.call(join)
40
+ end
41
+ else
42
+ block.call(join)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ # This is a 'fix' for the left outer joins
49
+ # rails way would be to call left_outer_joins so the join_type gets set to Arel::Nodes::OuterJoin
50
+ # Maybe this could be fixed in joining but I do not know how.
51
+ module Injector6_1 # :nodoc:
52
+ def make_constraints(parent, child, join_type) # :nodoc:
53
+ join_type = child.join_type if child.join_type == Arel::Nodes::OuterJoin
54
+ super(parent, child, join_type)
55
+ end
56
+ end
57
+
25
58
  class Builder # :nodoc:
26
59
  attr_reader :join_dependency
27
60
 
28
61
  def initialize(relation)
29
- @join_dependency = ::JoinDependency.from_relation(relation) do |join|
30
- :association_join if join.kind_of? BabySqueel::Join
31
- end
62
+ @join_dependency = build(relation, collect_joins(relation))
32
63
  end
33
64
 
34
65
  # Find the alias of a BabySqueel::Association, by passing
35
66
  # a list (in order of chaining) of associations and finding
36
67
  # the respective JoinAssociation at each level.
37
68
  def find_alias(associations)
38
- table = find_join_association(associations).table
39
- reconstruct_with_type_caster(table, associations)
69
+ if BabySqueel::ActiveRecord::VersionHelper.at_least_6_1?
70
+ # construct_tables! got removed by rails
71
+ # https://github.com/rails/rails/commit/590b045ee2c0906ff162e6658a184afb201865d7
72
+ #
73
+ # construct_tables_for_association! is a method from the polyamorous (ransack) gem
74
+ join_root = join_dependency.send(:join_root)
75
+ join_root.each_children do |parent, child|
76
+ join_dependency.construct_tables_for_association!(parent, child)
77
+ end
78
+ elsif BabySqueel::ActiveRecord::VersionHelper.at_least_5_2_3?
79
+ # If we tell join_dependency to construct its tables, Active Record
80
+ # handles building the correct aliases and attaching them to its
81
+ # JoinDepenencies.
82
+ join_dependency.send(:construct_tables!, join_dependency.send(:join_root))
83
+ end
84
+
85
+ join_association = find_join_association(associations)
86
+ join_association.table
40
87
  end
41
88
 
42
89
  private
43
90
 
91
+ Associations = ::ActiveRecord::Associations
92
+
44
93
  def find_join_association(associations)
45
- associations.inject(join_dependency.send(:join_root)) do |parent, assoc|
46
- parent.children.find do |join_association|
47
- reflections_equal?(
48
- assoc._reflection,
49
- join_association.reflection
50
- )
51
- end
94
+ current = join_dependency.send(:join_root)
95
+
96
+ associations.each do |association|
97
+ name = association._reflection.name
98
+ current = current.children.find { |c| c.reflection.name == name && klass_equal?(association, c) }
99
+ break if current.nil?
52
100
  end
101
+
102
+ current
53
103
  end
54
104
 
55
- # Compare two reflections and see if they're the same.
56
- def reflections_equal?(a, b)
57
- comparable_reflection(a) == comparable_reflection(b)
105
+ # If association is not polymorphic return true.
106
+ # If association is polymorphic compare the association polymorphic class with the join association base_klass
107
+ def klass_equal?(assoc, join_association)
108
+ return true unless assoc._reflection.polymorphic?
109
+
110
+ assoc._polymorphic_klass == join_association.base_klass
58
111
  end
59
112
 
60
- # Get the parent of the reflection if it has one.
61
- # In AR4, #parent_reflection returns [name, reflection]
62
- # In AR5, #parent_reflection returns just a reflection
63
- def comparable_reflection(reflection)
64
- [*reflection.parent_reflection].last || reflection
113
+ def collect_joins(relation)
114
+ joins = []
115
+ joins += relation.joins_values
116
+ joins += relation.left_outer_joins_values
117
+
118
+ buckets = joins.group_by do |join|
119
+ case join
120
+ when String
121
+ :string_join
122
+ when Hash, Symbol, Array
123
+ :association_join
124
+ when Associations::JoinDependency
125
+ :stashed_join
126
+ when Arel::Nodes::Join
127
+ :join_node
128
+ when BabySqueel::Join
129
+ :association_join
130
+ else
131
+ raise("unknown class: %s" % join.class.name)
132
+ end
133
+ end
65
134
  end
66
135
 
67
- # Active Record 5's AliasTracker initializes Arel tables
68
- # with the type_caster belonging to the wrong model.
69
- #
70
- # See: https://github.com/rails/rails/pull/27994
71
- def reconstruct_with_type_caster(table, associations)
72
- return table if ::ActiveRecord::VERSION::MAJOR < 5
73
- type_caster = associations.last._scope.type_caster
74
- ::Arel::Table.new(table.name, type_caster: type_caster)
136
+ def build(relation, buckets)
137
+ buckets.default = []
138
+ association_joins = buckets[:association_join]
139
+ stashed_association_joins = buckets[:stashed_join]
140
+ join_nodes = buckets[:join_node].uniq
141
+ string_joins = buckets[:string_join].map(&:strip).uniq
142
+
143
+ joins = string_joins.map do |join|
144
+ relation.table.create_string_join(Arel.sql(join)) unless join.blank?
145
+ end.compact
146
+
147
+ join_list = join_nodes + joins
148
+
149
+ alias_tracker = Associations::AliasTracker.create(relation.klass.connection, relation.table.name, join_list)
150
+ if BabySqueel::ActiveRecord::VersionHelper.at_least_6_0?
151
+ join_dependency = Associations::JoinDependency.new(relation.klass, relation.table, association_joins, Arel::Nodes::InnerJoin)
152
+ join_dependency.instance_variable_set(:@alias_tracker, alias_tracker)
153
+ elsif BabySqueel::ActiveRecord::VersionHelper.at_least_5_2_3?
154
+ join_dependency = Associations::JoinDependency.new(relation.klass, relation.table, association_joins)
155
+ join_dependency.instance_variable_set(:@alias_tracker, alias_tracker)
156
+ else
157
+ # Rails 5.2.0 - 5.2.2
158
+ join_dependency = Associations::JoinDependency.new(relation.klass, relation.table, association_joins, alias_tracker)
159
+ end
160
+ join_nodes.each do |join|
161
+ join_dependency.send(:alias_tracker).aliases[join.left.name.downcase] = 1
162
+ end
163
+
164
+ join_dependency
75
165
  end
76
166
  end
77
167
  end
@@ -1,3 +1,3 @@
1
1
  module BabySqueel
2
- VERSION = '1.3.1'.freeze
2
+ VERSION = '1.4.4'.freeze
3
3
  end
data/lib/baby_squeel.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  require 'active_record'
2
2
  require 'active_record/relation'
3
- require 'polyamorous'
3
+ begin
4
+ require 'polyamorous'
5
+ rescue LoadError
6
+ # Trying loading from 'ransack' as of commit c9cc20de9 (post v2.3.2)
7
+ require 'polyamorous/polyamorous'
8
+ end
4
9
  require 'baby_squeel/version'
5
10
  require 'baby_squeel/errors'
6
11
  require 'baby_squeel/active_record/base'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: baby_squeel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ray Zane
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-15 00:00:00.000000000 Z
11
+ date: 2022-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,84 +16,76 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.0
19
+ version: '5.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '7.1'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: 4.2.0
27
- - !ruby/object:Gem::Dependency
28
- name: polyamorous
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.3'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
29
+ version: '5.2'
30
+ - - "<"
39
31
  - !ruby/object:Gem::Version
40
- version: '1.3'
32
+ version: '7.1'
41
33
  - !ruby/object:Gem::Dependency
42
- name: join_dependency
34
+ name: ransack
43
35
  requirement: !ruby/object:Gem::Requirement
44
36
  requirements:
45
37
  - - "~>"
46
38
  - !ruby/object:Gem::Version
47
- version: 0.1.2
39
+ version: '2.3'
48
40
  type: :runtime
49
41
  prerelease: false
50
42
  version_requirements: !ruby/object:Gem::Requirement
51
43
  requirements:
52
44
  - - "~>"
53
45
  - !ruby/object:Gem::Version
54
- version: 0.1.2
46
+ version: '2.3'
55
47
  - !ruby/object:Gem::Dependency
56
48
  name: bundler
57
49
  requirement: !ruby/object:Gem::Requirement
58
50
  requirements:
59
51
  - - "~>"
60
52
  - !ruby/object:Gem::Version
61
- version: '1.11'
53
+ version: '2'
62
54
  type: :development
63
55
  prerelease: false
64
56
  version_requirements: !ruby/object:Gem::Requirement
65
57
  requirements:
66
58
  - - "~>"
67
59
  - !ruby/object:Gem::Version
68
- version: '1.11'
60
+ version: '2'
69
61
  - !ruby/object:Gem::Dependency
70
62
  name: rake
71
63
  requirement: !ruby/object:Gem::Requirement
72
64
  requirements:
73
65
  - - "~>"
74
66
  - !ruby/object:Gem::Version
75
- version: '10.0'
67
+ version: '13.0'
76
68
  type: :development
77
69
  prerelease: false
78
70
  version_requirements: !ruby/object:Gem::Requirement
79
71
  requirements:
80
72
  - - "~>"
81
73
  - !ruby/object:Gem::Version
82
- version: '10.0'
74
+ version: '13.0'
83
75
  - !ruby/object:Gem::Dependency
84
76
  name: rspec
85
77
  requirement: !ruby/object:Gem::Requirement
86
78
  requirements:
87
79
  - - "~>"
88
80
  - !ruby/object:Gem::Version
89
- version: 3.4.0
81
+ version: '3.10'
90
82
  type: :development
91
83
  prerelease: false
92
84
  version_requirements: !ruby/object:Gem::Requirement
93
85
  requirements:
94
86
  - - "~>"
95
87
  - !ruby/object:Gem::Version
96
- version: 3.4.0
88
+ version: '3.10'
97
89
  - !ruby/object:Gem::Dependency
98
90
  name: sqlite3
99
91
  requirement: !ruby/object:Gem::Requirement
@@ -124,6 +116,7 @@ files:
124
116
  - lib/baby_squeel/active_record/base.rb
125
117
  - lib/baby_squeel/active_record/calculations.rb
126
118
  - lib/baby_squeel/active_record/query_methods.rb
119
+ - lib/baby_squeel/active_record/version_helper.rb
127
120
  - lib/baby_squeel/active_record/where_chain.rb
128
121
  - lib/baby_squeel/association.rb
129
122
  - lib/baby_squeel/calculation.rb
@@ -140,7 +133,6 @@ files:
140
133
  - lib/baby_squeel/nodes/node.rb
141
134
  - lib/baby_squeel/nodes/proxy.rb
142
135
  - lib/baby_squeel/operators.rb
143
- - lib/baby_squeel/pluck.rb
144
136
  - lib/baby_squeel/relation.rb
145
137
  - lib/baby_squeel/resolver.rb
146
138
  - lib/baby_squeel/table.rb
@@ -149,7 +141,7 @@ homepage: https://github.com/rzane/baby_squeel
149
141
  licenses:
150
142
  - MIT
151
143
  metadata: {}
152
- post_install_message:
144
+ post_install_message:
153
145
  rdoc_options: []
154
146
  require_paths:
155
147
  - lib
@@ -164,9 +156,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
156
  - !ruby/object:Gem::Version
165
157
  version: '0'
166
158
  requirements: []
167
- rubyforge_project:
168
- rubygems_version: 2.7.6
169
- signing_key:
159
+ rubygems_version: 3.3.3
160
+ signing_key:
170
161
  specification_version: 4
171
162
  summary: An expressive query DSL for Active Record 4 and 5.
172
163
  test_files: []
@@ -1,25 +0,0 @@
1
- module BabySqueel
2
- class Pluck # :nodoc:
3
- # In Active Record 4.2, #pluck chokes when you give it
4
- # Arel. It calls #to_s on whatever you pass in. So the
5
- # hacky solution is to wrap the node in a class that
6
- # returns the node when you call #to_s. Then, it works!
7
- #
8
- # In Active Record 5, #pluck accepts Arel, so we won't
9
- # bother to use this there.
10
-
11
- if ::ActiveRecord::VERSION::MAJOR >= 5
12
- def self.decorate(node); node; end
13
- else
14
- def self.decorate(node); new(node); end
15
- end
16
-
17
- def initialize(node)
18
- @node = node
19
- end
20
-
21
- def to_s
22
- @node
23
- end
24
- end
25
- end