baby_squeel 1.3.0 → 1.4.2

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: af276fe0363304d4906df4766ea988557406c2328d3ebc09e3e6c6ff020970bc
4
- data.tar.gz: a2657f186940a7306b8d891883a7e0f182bcf5d8af54239fc8de4bf678d34ab1
3
+ metadata.gz: 154cc7b5379993dfa67f76c182bfe810f5c9b941930ec69e386270e5751201da
4
+ data.tar.gz: 873324d4d500c03621c6a3fb20321a948f2b9ae9dadf098aff028b154dc57f36
5
5
  SHA512:
6
- metadata.gz: be1242d3245214970d7c295014e0caf931ccf93193ff0a37b868557334a2382df346385f36c4a06c8079f1b358a695ba557eb8d55f68a925491fc8524008e831
7
- data.tar.gz: 5812711b6fd09a716e1b8d5959a2c15103611807d61cbe92c52ff36fb08785bc6226943847c6e921369fc78fda0479768a0eae306d278268e54433dac6144d19
6
+ metadata.gz: b29e8eb5d1225e3e8f00908af60da6b5deeebeb49467a52aa875fcad70972002d312dac0151be4d4ca7562012cc7c21593c630f1b44b2f20733cb43bdc997854
7
+ data.tar.gz: 3b3b9957bc49729ffdcf5bda14ef4446816cf8cbd12facf67a30ec8912bbb260e0a0543334a3e840a0d691ee8d990754dbe23e687129321b88a46360b2d60e76
data/CHANGELOG.md CHANGED
@@ -1,130 +1,212 @@
1
1
  ## [Unreleased]
2
2
 
3
- Nothing to see here.
3
+ ## [1.4.2] - 2022-01-24
4
+
5
+ ### Fixed
6
+
7
+ - Added support for activerecord 7.0 (#116)
8
+ - Added support for activerecord 6.1 (#116)
9
+ - Added support for activerecord 6.0 (#116)
10
+
11
+ ## [1.4.1] - 2021-06-17
12
+
13
+ ### Fixed
14
+
15
+ - Fixed a bug related to checking the Active Record version.
16
+
17
+ ## [1.4.0] - 2021-06-17
18
+
19
+ ### Fixed
20
+
21
+ - Fix table alias when joining a polymorphic table twice (#108)
22
+ - Removed internal class `BabySqueel::Pluck`. You can still use `plucking`. For example, `Post.joining { author }.plucking { author.name }`
23
+ - Removed old code from Active Record < 5.2
24
+ - Removed dependency `join_dependency`
25
+
26
+ ## [1.4.0.beta1] - 2021-04-21
27
+
28
+ ### Fixed
29
+
30
+ - Add Support for activerecord '>= 5.2.3'
31
+ - Drop Support for Active Record versions that have reached EOL (activerecord < 5.2)
32
+ - Use polyamorous from ransack '~> 2.3'
33
+
34
+ ## [1.3.1] - 2018-05-15
35
+
36
+ ### Fixed
37
+
38
+ - Upgraded `join_dependency` requirement, which fixes [issue #1](https://github.com/rzane/join_dependency/issues/1).
4
39
 
5
40
  ## [1.3.0] - 2018-05-04
6
- ## Added
41
+
42
+ ### Added
43
+
7
44
  - The ability to use `plucking` with an array of nodes. For example, `User.plucking { [id, name] }`.
8
45
 
9
46
  ## [1.2.1] - 2018-04-25
10
- ## Fixed
47
+
48
+ ### Fixed
49
+
11
50
  - Added support for Active Record 5.2
12
51
 
13
52
  ## [1.2.0] - 2017-10-20
53
+
14
54
  ### Added
55
+
15
56
  - `reordering`, which is just a BabySqueel version of Active Record's `reorder`.
16
57
  - `on` expressions can now be given a block that will yield the current node (#77).
17
58
 
18
59
  ## [1.1.5] - 2017-05-26
60
+
19
61
  ### Fixed
62
+
20
63
  - Returning an empty hash from a `where.has {}` block would generate invalid SQL (#69).
21
64
 
22
65
  ## [1.1.4] - 2017-04-13
66
+
23
67
  ### Fixed
68
+
24
69
  - Nodes::Attribute#in and #not_in generate valid SQL when given ActiveRecord::NullRelations.
25
70
 
26
71
  ## [1.1.3] - 2017-03-31
72
+
27
73
  ### Fixed
74
+
28
75
  - Nodes::Attribute#in was not returning BabySqueel node. As a result, you couldn't chain on it. This fixes #61.
29
76
 
30
77
  ## [1.1.2] - 2017-03-21
78
+
31
79
  ### Fixed
80
+
32
81
  - Check if a reflection has a parent reflection before comparing them. This fixes #56.
33
82
 
34
83
  ### Refactored
84
+
35
85
  - 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.
36
86
 
37
87
  ## [1.1.1] - 2017-02-14
88
+
38
89
  ### Fixed
90
+
39
91
  - 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).
40
92
 
41
93
  ## [1.1.0] - 2017-02-10
94
+
42
95
  > 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.
43
96
 
44
97
  ### Added
98
+
45
99
  - DSLs for ActiveRecord::Relation::Calculations. You can now use `plucking`, `counting`, `summing`, `averaging`, `minimizing`, and `maximizing`.
46
100
 
47
101
  ## [1.0.3] - 2017-02-09
102
+
48
103
  ### Added
104
+
49
105
  - Support for `pluck`.
50
106
  - Support for `not_in`.
51
107
 
52
108
  ## [1.0.2] - 2017-02-07
109
+
53
110
  ### Added
111
+
54
112
  - `BabySqueel::Association` now has `#==` and `#!=`. This is only supported for Rails 5+. Example: `Post.where { author: Author.last }`.
55
113
 
56
114
  ### Fixed
115
+
57
116
  - Incorrect alias detection caused by not tracking the full path to a join (#37).
58
117
 
59
118
  ## [1.0.1] - 2016-11-07
119
+
60
120
  ### Added
61
- - Add DSL#_ for wrapping expressions in Arel::Node::Grouping. Thanks to [@odedniv].
121
+
122
+ - Add DSL#\_ for wrapping expressions in Arel::Node::Grouping. Thanks to [@odedniv].
62
123
 
63
124
  ### Fixed
125
+
64
126
  - Use strings for attribute names like Rails does. Symbols were preventing things like `unscope` from working. Thanks to [@chewi].
65
127
  - `where.has {}` will now accept `nil`.
66
128
  - Arel::Nodes::Function did not previously include Arel::Math, so now you can do math operations on the result of SQL functions.
67
129
  - Arel::Nodes::Binary did not previously include Arel::AliasPredication. Binary nodes can now be aliased using `as`.
68
130
 
69
131
  ## [1.0.0] - 2016-09-09
132
+
70
133
  ### Added
71
- - 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.
134
+
135
+ - 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.
72
136
  - Within DSL blocks, you can use `exists` and `not_exists` with Active Record relations. For example: `Post.where.has { exists Post.where(title: 'Fun') }`.`
73
137
  - Support for polymorphic associations.
74
138
 
75
139
  ### Deprecations
140
+
76
141
  - Removed support for Active Record 4.0.x
77
142
 
78
143
  ### Changed
144
+
79
145
  - 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.
80
146
  - BabySqueel::Nodes::Generic is now BabySqueel::Nodes::Node.
81
147
  - 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`.
82
148
 
83
149
  ### Fixed
150
+
84
151
  - Fixed deprecation warnings on Active Record 5 when initializing an Arel::Table without a type caster.
85
152
  - No more duplicate joins. Previously, Baby Squeel did a very poor job of ensuring that you didn't join an association twice.
86
- - Alias detection should now *actually* work. The previous implementation was naive.
153
+ - Alias detection should now _actually_ work. The previous implementation was naive.
87
154
 
88
155
  ## [0.3.1] - 2016-08-02
156
+
89
157
  ### Added
158
+
90
159
  - Ported backticks and #my from Squeel
91
160
 
92
161
  ### Changed
162
+
93
163
  - DSL#sql now returns a node wrapped in a BabySqueel proxy.
94
164
 
95
165
  ## [0.3.0] - 2016-06-26
166
+
96
167
  ### Added
168
+
97
169
  - Added Squeel compatibility mode that allows `select`, `order`, `joins`, `group`, `where`, and `having` to accept DSL blocks.
98
170
  - Added the ability to query tables that aren't backed by Active Record models.
99
171
  - Added `BabySqueel::[]`, which provides a `BabySqueel::Relation` for models, or a `BabySqueel::Table` for symbols/strings.
100
172
 
101
173
  ### Changed
174
+
102
175
  - Renamed `BabySqueel::Association::AliasingError` to `BabySqueel::AssociationAliasingError`.
103
176
 
104
177
  ## [0.2.2] - 2016-03-30
178
+
105
179
  ### Added
180
+
106
181
  - Support for `group` (`grouping`) and `having` (`when_having`).
107
182
  - Support for sifters.
108
183
  - Added `quoted` and `sql` helpers for quoting strings and SQL literals.
109
184
  - More descriptive error messages when a column or association is not found.
110
185
 
111
186
  ### Fixed
187
+
112
188
  - `Arel::Nodes::Grouping` does not include `Arel::Math`, so operations like `(id + 5) + 3` would fail unexpectedly.
113
189
  - Fix missing bind values When joining through associations with default scope.
114
190
  - Removed `ActiveRecord::VERSION` specific handling of the `WhereChain`.
115
191
 
116
192
  ## [0.2.1] - 2016-03-27
193
+
117
194
  ### Added
195
+
118
196
  - Support for subqueries.
119
197
 
120
198
  ### Fixed
199
+
121
200
  - Some Arel nodes did not have access to `as` expressions.
122
201
 
123
202
  ## [0.2.0] - 2016-03-25
203
+
124
204
  ### Added
205
+
125
206
  - References to aliased joins in a `select`, `where`, or `order` expression now use the aliased table name.
126
207
 
127
208
  ### Changed
209
+
128
210
  - Rely on `ActiveRecord::Relation#join_sources` for the implicit construction of join nodes, rather than using the `ActiveRecord::Associations::JoinDependency` directly.
129
211
 
130
212
  ### Fixed
@@ -132,10 +214,17 @@ Nothing to see here.
132
214
  - Associations referencing the same table weren't being aliased.
133
215
 
134
216
  ## [0.1.0] - 2016-03-16
217
+
135
218
  ### Added
219
+
136
220
  - Initial support for selects, orders, wheres, and joins.
137
221
 
138
- [Unreleased]: https://github.com/rzane/baby_squeel/compare/v1.3.0...HEAD
222
+ [unreleased]: https://github.com/rzane/baby_squeel/compare/v1.4.2...HEAD
223
+ [1.4.2]: https://github.com/rzane/baby_squeel/compare/v1.4.1...v1.4.2
224
+ [1.4.1]: https://github.com/rzane/baby_squeel/compare/v1.4.0...v1.4.1
225
+ [1.4.0]: https://github.com/rzane/baby_squeel/compare/v1.4.0.beta1...v1.4.0
226
+ [1.4.0.beta1]: https://github.com/rzane/baby_squeel/compare/v1.3.1...v1.4.0.beta1
227
+ [1.3.1]: https://github.com/rzane/baby_squeel/compare/v1.3.0...v1.3.1
139
228
  [1.3.0]: https://github.com/rzane/baby_squeel/compare/v1.2.1...v1.3.0
140
229
  [1.2.1]: https://github.com/rzane/baby_squeel/compare/v1.2.0...v1.2.1
141
230
  [1.2.0]: https://github.com/rzane/baby_squeel/compare/v1.1.5...v1.2.0
@@ -154,6 +243,5 @@ Nothing to see here.
154
243
  [0.2.2]: https://github.com/rzane/baby_squeel/compare/v0.2.1...v0.2.2
155
244
  [0.2.1]: https://github.com/rzane/baby_squeel/compare/v0.2.0...v0.2.1
156
245
  [0.2.0]: https://github.com/rzane/baby_squeel/compare/v0.1.0...v0.2.0
157
-
158
246
  [@chewi]: https://github.com/chewi
159
247
  [@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.1'
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)
@@ -36,17 +53,31 @@ module BabySqueel
36
53
 
37
54
  private
38
55
 
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
56
+ if BabySqueel::ActiveRecord::VersionHelper.at_least_6_1?
57
+ # https://github.com/rails/rails/commit/c0c53ee9d28134757cf1418521cb97c4a135f140
58
+ def select_association_list(*args)
59
+ args[0].extend(BabySqueel::ActiveRecord::QueryMethods::Injector6_1)
60
+ super *args
61
+ end
62
+
63
+ def construct_join_dependency(associations, join_type)
64
+ super(associations, join_type).extend(BabySqueel::JoinDependency::Injector6_1)
65
+ end
66
+ elsif BabySqueel::ActiveRecord::VersionHelper.at_least_6_0?
67
+ # Active Record will call `each` on the `joins`. The
68
+ # Injector has a custom `each` method that handles
69
+ # BabySqueel::Join nodes.
70
+ def build_joins(*args)
71
+ args[1] = BabySqueel::JoinDependency::Injector6_0.new(args.second)
72
+ super(*args)
46
73
  end
47
74
  else
48
- def build_joins(manager, joins)
49
- super manager, BabySqueel::JoinDependency::Injector.new(joins)
75
+ # Active Record will call `group_by` on the `joins`. The
76
+ # Injector has a custom `group_by` method that handles
77
+ # BabySqueel::Join nodes.
78
+ def build_joins(*args)
79
+ args[1] = BabySqueel::JoinDependency::Injector5_2.new(args.second)
80
+ super(*args)
50
81
  end
51
82
  end
52
83
  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
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.0'.freeze
2
+ VERSION = '1.4.2'.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.0
4
+ version: 1.4.2
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-04 00:00:00.000000000 Z
11
+ date: 2022-01-25 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.1
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.1
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.2.22
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