squeel 1.1.1 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +3 -0
- data/.travis.yml +36 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile +1 -1
- data/README.md +47 -6
- data/Rakefile +14 -2
- data/lib/squeel.rb +9 -1
- data/lib/squeel/adapters/active_record.rb +0 -1
- data/lib/squeel/adapters/active_record/3.0/join_dependency_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/3.0/relation_extensions.rb +12 -1
- data/lib/squeel/adapters/active_record/3.1/join_dependency_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/3.2/join_dependency_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/4.0/join_dependency_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/4.0/relation_extensions.rb +92 -0
- data/lib/squeel/adapters/active_record/4.1/compat.rb +15 -0
- data/lib/squeel/adapters/active_record/4.1/context.rb +88 -0
- data/lib/squeel/adapters/active_record/4.1/preloader_extensions.rb +31 -0
- data/lib/squeel/adapters/active_record/4.1/reflection_extensions.rb +37 -0
- data/lib/squeel/adapters/active_record/4.1/relation_extensions.rb +307 -0
- data/lib/squeel/adapters/active_record/4.2/compat.rb +1 -0
- data/lib/squeel/adapters/active_record/4.2/context.rb +1 -0
- data/lib/squeel/adapters/active_record/4.2/preloader_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/4.2/relation_extensions.rb +108 -0
- data/lib/squeel/adapters/active_record/context.rb +7 -7
- data/lib/squeel/adapters/active_record/join_dependency_extensions.rb +9 -13
- data/lib/squeel/adapters/active_record/relation_extensions.rb +38 -8
- data/lib/squeel/core_ext/symbol.rb +3 -3
- data/lib/squeel/dsl.rb +1 -1
- data/lib/squeel/nodes.rb +1 -0
- data/lib/squeel/nodes/as.rb +12 -0
- data/lib/squeel/nodes/join.rb +8 -4
- data/lib/squeel/nodes/key_path.rb +10 -1
- data/lib/squeel/nodes/node.rb +21 -0
- data/lib/squeel/nodes/stub.rb +8 -4
- data/lib/squeel/nodes/subquery_join.rb +44 -0
- data/lib/squeel/version.rb +1 -1
- data/lib/squeel/visitors.rb +2 -0
- data/lib/squeel/visitors/enumeration_visitor.rb +101 -0
- data/lib/squeel/visitors/order_visitor.rb +9 -2
- data/lib/squeel/visitors/predicate_visitor.rb +11 -0
- data/lib/squeel/visitors/preload_visitor.rb +12 -0
- data/lib/squeel/visitors/visitor.rb +89 -13
- data/spec/config.travis.yml +13 -0
- data/spec/config.yml +12 -0
- data/spec/console.rb +3 -12
- data/spec/core_ext/symbol_spec.rb +3 -3
- data/spec/helpers/squeel_helper.rb +8 -5
- data/spec/spec_helper.rb +4 -16
- data/spec/squeel/adapters/active_record/context_spec.rb +8 -4
- data/spec/squeel/adapters/active_record/join_dependency_extensions_spec.rb +123 -38
- data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +350 -124
- data/spec/squeel/core_ext/symbol_spec.rb +3 -3
- data/spec/squeel/nodes/join_spec.rb +4 -4
- data/spec/squeel/nodes/stub_spec.rb +3 -3
- data/spec/squeel/nodes/subquery_join_spec.rb +46 -0
- data/spec/squeel/visitors/order_visitor_spec.rb +3 -3
- data/spec/squeel/visitors/predicate_visitor_spec.rb +69 -36
- data/spec/squeel/visitors/select_visitor_spec.rb +1 -1
- data/spec/squeel/visitors/visitor_spec.rb +7 -6
- data/spec/support/models.rb +99 -15
- data/spec/support/schema.rb +109 -4
- data/squeel.gemspec +8 -6
- metadata +89 -107
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/spec/blueprints/articles.rb +0 -5
- data/spec/blueprints/comments.rb +0 -5
- data/spec/blueprints/notes.rb +0 -3
- data/spec/blueprints/people.rb +0 -4
- data/spec/blueprints/tags.rb +0 -3
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3d3196690094de459e3e30179f68ce63ee2032e1
|
4
|
+
data.tar.gz: 827a3e061d72e29cac9b615cbc3fb66c6c1e3462
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fcf69aceda5afe483dfad4a91d40b21d8472b250c5a9eb719afaa6ccc1252d9488d176c0cc9d41d7a68e18a66f0dd5ff33dbcf4d77b59fd12c673e311cae680c
|
7
|
+
data.tar.gz: 6a934cabda1f179d9a920cf4974fe8776b68d4a58578ee2c067ae4f1e7fac78a0989268920e711845d78367d66521c297e0cb8215e5d8fe85b336d275ae0d249
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
CHANGED
@@ -1,8 +1,40 @@
|
|
1
|
+
before_script:
|
2
|
+
- mysql -e "create database squeel_test_examples;"
|
3
|
+
- psql -c "create database squeel_test_examples;" -U postgres
|
4
|
+
|
5
|
+
script:
|
6
|
+
- bundle exec rake test:$ADAPTER
|
7
|
+
|
1
8
|
rvm:
|
2
9
|
- 1.9.3
|
10
|
+
- 2.0.0
|
11
|
+
- 2.1.1
|
12
|
+
- 2.1.2
|
3
13
|
|
4
14
|
env:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
15
|
+
global:
|
16
|
+
- SQ_CONFIG_FILE=$TRAVIS_BUILD_DIR/spec/config.travis.yml
|
17
|
+
matrix:
|
18
|
+
- RAILS=master AREL=master ADAPTER=sqlite3
|
19
|
+
- RAILS=4-1-stable AREL=5-0-stable ADAPTER=sqlite3
|
20
|
+
- RAILS=4-0-stable AREL=4-0-stable ADAPTER=sqlite3
|
21
|
+
- RAILS=3-2-stable AREL=3-0-stable ADAPTER=sqlite3
|
22
|
+
- RAILS=3-1-stable AREL=2-2-stable ADAPTER=sqlite3
|
23
|
+
- RAILS=3-0-stable AREL=2-0-stable ADAPTER=sqlite3
|
24
|
+
- RAILS=master AREL=master ADAPTER=mysql
|
25
|
+
- RAILS=4-1-stable AREL=5-0-stable ADAPTER=mysql
|
26
|
+
- RAILS=4-0-stable AREL=4-0-stable ADAPTER=mysql
|
27
|
+
- RAILS=3-2-stable AREL=3-0-stable ADAPTER=mysql
|
28
|
+
- RAILS=3-1-stable AREL=2-2-stable ADAPTER=mysql
|
29
|
+
- RAILS=3-0-stable AREL=2-0-stable ADAPTER=mysql
|
30
|
+
- RAILS=master AREL=master ADAPTER=mysql2
|
31
|
+
- RAILS=4-1-stable AREL=5-0-stable ADAPTER=mysql2
|
32
|
+
- RAILS=4-0-stable AREL=4-0-stable ADAPTER=mysql2
|
33
|
+
- RAILS=3-2-stable AREL=3-0-stable ADAPTER=mysql2
|
34
|
+
- RAILS=3-1-stable AREL=2-2-stable ADAPTER=mysql2
|
35
|
+
- RAILS=master AREL=master ADAPTER=postgresql
|
36
|
+
- RAILS=4-1-stable AREL=5-0-stable ADAPTER=postgresql
|
37
|
+
- RAILS=4-0-stable AREL=4-0-stable ADAPTER=postgresql
|
38
|
+
- RAILS=3-2-stable AREL=3-0-stable ADAPTER=postgresql
|
39
|
+
- RAILS=3-1-stable AREL=2-2-stable ADAPTER=postgresql
|
40
|
+
- RAILS=3-0-stable AREL=2-0-stable ADAPTER=postgresql
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## 1.2.1 (Unreleased)
|
2
|
+
|
3
|
+
* Run all specs against sqlite, mysql and postgresql!
|
4
|
+
* Genereta table names correctly when joining through an association. Fixes#302.
|
5
|
+
* Enable Arel nodes in Squeel with "|" operator. Fixes #314.
|
6
|
+
* Properly append binds from a relation used in a subquery. Fixes #272.
|
7
|
+
|
8
|
+
## 1.2.0 (2014-07-16)
|
9
|
+
|
10
|
+
* Add compatibility to Ruby 2.0+ with Rails 4.1 and 4.2.0.alpha.
|
11
|
+
Fixes #301, #305, #307
|
12
|
+
* Enable using a relation as a subquery. Fixes #309
|
13
|
+
* Bind params correctly in subquery using associations. Fixes #312
|
14
|
+
* Use the correct attribute name when finding a Join node. Fixes #273.
|
15
|
+
|
1
16
|
## 1.1.1 (2013-09-03)
|
2
17
|
|
3
18
|
* Update relation extensions to support new count behavior in Active Record
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Squeel [![Build Status](https://secure.travis-ci.org/
|
1
|
+
# Squeel [![Build Status](https://secure.travis-ci.org/activerecord-hackery/squeel.png)](http://travis-ci.org/activerecord-hackery/squeel) [![endorse](http://api.coderwall.com/ernie/endorsecount.png)](http://coderwall.com/ernie)
|
2
2
|
|
3
3
|
Squeel lets you write your Active Record queries with fewer strings, and more Ruby,
|
4
4
|
by making the Arel awesomeness that lies beneath Active Record more accessible.
|
@@ -23,8 +23,10 @@ just a simple example -- Squeel's capable of a whole lot more. Keep reading.
|
|
23
23
|
In your Gemfile:
|
24
24
|
|
25
25
|
```ruby
|
26
|
+
# Make sure you are using the latest version of polyamorous
|
27
|
+
gem "polyamorous", :git => "git://github.com/activerecord-hackery/polyamorous.git"
|
26
28
|
gem "squeel" # Last officially released gem
|
27
|
-
# gem "squeel", :git => "git://github.com/
|
29
|
+
# gem "squeel", :git => "git://github.com/activerecord-hackery/squeel.git" # Track git repo
|
28
30
|
```
|
29
31
|
|
30
32
|
Then bundle as usual.
|
@@ -86,6 +88,24 @@ A Squeel keypath is essentially a more concise and readable alternative to a
|
|
86
88
|
deeply nested hash. For instance, in standard Active Record, you might join several
|
87
89
|
associations like this to perform a query:
|
88
90
|
|
91
|
+
#### Rails 4+
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
Person.joins(:articles => {:comments => :person}).references(:all)
|
95
|
+
# => SELECT "people".* FROM "people"
|
96
|
+
# LEFT OUTER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
97
|
+
# LEFT OUTER JOIN "comments" ON "comments"."article_id" = "articles"."id"
|
98
|
+
# LEFT OUTER JOIN "people" "people_comments" ON "people_comments"."id" = "comments"."person_id"
|
99
|
+
```
|
100
|
+
|
101
|
+
With a keypath, this would look like:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
Person.joins{articles.comments.person}.references(:all)
|
105
|
+
```
|
106
|
+
|
107
|
+
#### Rails 3.x
|
108
|
+
|
89
109
|
```ruby
|
90
110
|
Person.joins(:articles => {:comments => :person})
|
91
111
|
# => SELECT "people".* FROM "people"
|
@@ -413,6 +433,27 @@ Person.joins{children.parent.children}.
|
|
413
433
|
|
414
434
|
Keypaths were used here for clarity, but nested hashes would work just as well.
|
415
435
|
|
436
|
+
You can also use a subquery in a join.
|
437
|
+
|
438
|
+
Notice:
|
439
|
+
1. Squeel can only accept an ActiveRecord::Relation class of subqueries in a join.
|
440
|
+
2. Use the chain with caution. You should call `as` first to get a Nodes::As, then call `on` to get a join node.
|
441
|
+
|
442
|
+
```ruby
|
443
|
+
subquery = OrderItem.group(:orderable_id).select { [orderable_id, sum(quantity * unit_price).as(amount)] }
|
444
|
+
Seat.joins { [payment.outer, subquery.as('seat_order_items').on { id == seat_order_items.orderable_id}.outer] }.
|
445
|
+
select { [seat_order_items.amount, "seats.*"] }
|
446
|
+
# => SELECT "seat_order_items"."amount", seats.*
|
447
|
+
# FROM "seats"
|
448
|
+
# LEFT OUTER JOIN "payments" ON "payments"."id" = "seats"."payment_id"
|
449
|
+
# LEFT OUTER JOIN (
|
450
|
+
# SELECT "order_items"."orderable_id",
|
451
|
+
# sum("order_items"."quantity" * "order_items"."unit_price") AS amount
|
452
|
+
# FROM "order_items"
|
453
|
+
# GROUP BY "order_items"."orderable_id"
|
454
|
+
# ) seat_order_items ON "seats"."id" = "seat_order_items"."orderable_id"
|
455
|
+
```
|
456
|
+
|
416
457
|
### Functions
|
417
458
|
|
418
459
|
You can call SQL functions just like you would call a method in Ruby...
|
@@ -470,7 +511,7 @@ As you can see, just like functions, these operations can be given aliases.
|
|
470
511
|
To select more than one attribute (or calculated attribute) simply put them into an array:
|
471
512
|
|
472
513
|
```ruby
|
473
|
-
p = Person.select{[ name.op('||', '-diddly').as(flanderized_name),
|
514
|
+
p = Person.select{[ name.op('||', '-diddly').as(flanderized_name),
|
474
515
|
coalesce(name, '<no name given>').as(name_with_default) ]}.first
|
475
516
|
p.flanderized_name
|
476
517
|
# => "Aric Smith-diddly"
|
@@ -537,9 +578,9 @@ For further information, see
|
|
537
578
|
[this post to the Rails list](https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-core/NQJJzZ7R7S0),
|
538
579
|
[this commit](https://github.com/lifo/docrails/commit/50c5005bafe7e43f81a141cd2c512379aec74325) to
|
539
580
|
the [Active Record guides](http://edgeguides.rubyonrails.org/active_record_querying.html#hash-conditions),
|
540
|
-
[#67](https://github.com/
|
541
|
-
[#75](https://github.com/
|
542
|
-
[#171](https://github.com/
|
581
|
+
[#67](https://github.com/activerecord-hackery/squeel/issues/67),
|
582
|
+
[#75](https://github.com/activerecord-hackery/squeel/issues/75), and
|
583
|
+
[#171](https://github.com/activerecord-hackery/squeel/issues/171).
|
543
584
|
|
544
585
|
## Compatibility with MetaWhere
|
545
586
|
|
data/Rakefile
CHANGED
@@ -4,10 +4,22 @@ require 'rspec/core/rake_task'
|
|
4
4
|
Bundler::GemHelper.install_tasks
|
5
5
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec) do |rspec|
|
7
|
-
rspec.rspec_opts = ['--backtrace']
|
7
|
+
rspec.rspec_opts = ['--backtrace', '--color', '--format documentation']
|
8
8
|
end
|
9
9
|
|
10
|
-
task :default =>
|
10
|
+
task :default => 'test_sqlite3'
|
11
|
+
|
12
|
+
%w(sqlite3 mysql mysql2 postgresql).each do |adapter|
|
13
|
+
namespace :test do
|
14
|
+
task(adapter => ["#{adapter}:env", "spec"])
|
15
|
+
end
|
16
|
+
|
17
|
+
namespace adapter do
|
18
|
+
task(:env) { ENV['SQ_DB'] = adapter }
|
19
|
+
end
|
20
|
+
|
21
|
+
task "test_#{adapter}" => ["#{adapter}:env", "test:#{adapter}"]
|
22
|
+
end
|
11
23
|
|
12
24
|
desc "Open an irb session with Squeel and the sample data used in specs"
|
13
25
|
task :console do
|
data/lib/squeel.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
require 'squeel/configuration'
|
2
|
+
require 'polyamorous'
|
2
3
|
|
3
4
|
module Squeel
|
4
5
|
|
6
|
+
if defined?(Arel::InnerJoin)
|
7
|
+
InnerJoin = Arel::InnerJoin
|
8
|
+
OuterJoin = Arel::OuterJoin
|
9
|
+
else
|
10
|
+
InnerJoin = Arel::Nodes::InnerJoin
|
11
|
+
OuterJoin = Arel::Nodes::OuterJoin
|
12
|
+
end
|
13
|
+
|
5
14
|
extend Configuration
|
6
15
|
|
7
16
|
# Prevent warnings on the console when doing things some might describe as "evil"
|
@@ -30,7 +39,6 @@ module Squeel
|
|
30
39
|
alias_predicate aliaz, original
|
31
40
|
end
|
32
41
|
end
|
33
|
-
|
34
42
|
end
|
35
43
|
|
36
44
|
require 'squeel/dsl'
|
@@ -1,7 +1,6 @@
|
|
1
1
|
case ActiveRecord::VERSION::MAJOR
|
2
2
|
when 3, 4
|
3
3
|
ActiveRecord::Relation.send :include, Squeel::Nodes::Aliasing
|
4
|
-
require 'squeel/adapters/active_record/join_dependency_extensions'
|
5
4
|
require 'squeel/adapters/active_record/base_extensions'
|
6
5
|
|
7
6
|
adapter_directory = "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'squeel/adapters/active_record/join_dependency_extensions'
|
@@ -54,8 +54,9 @@ module Squeel
|
|
54
54
|
end
|
55
55
|
|
56
56
|
stashed_association_joins = joins.grep(::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation)
|
57
|
+
subquery_joins = joins.grep(Nodes::SubqueryJoin)
|
57
58
|
|
58
|
-
non_association_joins = (joins - association_joins - stashed_association_joins)
|
59
|
+
non_association_joins = (joins - association_joins - stashed_association_joins - subquery_joins)
|
59
60
|
custom_joins = custom_join_sql(*non_association_joins)
|
60
61
|
|
61
62
|
self.join_dependency = JoinDependency.new(@klass, association_joins, custom_joins)
|
@@ -79,6 +80,16 @@ module Squeel
|
|
79
80
|
relation = relation.join(left, join_type).on(*right)
|
80
81
|
end
|
81
82
|
|
83
|
+
subquery_joins.each do |join|
|
84
|
+
relation = relation.
|
85
|
+
join(
|
86
|
+
Arel::Nodes::TableAlias.new(
|
87
|
+
join.subquery.right,
|
88
|
+
Arel::Nodes::Grouping.new(join.subquery.left.arel.ast)),
|
89
|
+
join.type).
|
90
|
+
on(*where_visit(join.constraints))
|
91
|
+
end
|
92
|
+
|
82
93
|
relation = relation.join(custom_joins)
|
83
94
|
end
|
84
95
|
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'squeel/adapters/active_record/join_dependency_extensions'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'squeel/adapters/active_record/join_dependency_extensions'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'squeel/adapters/active_record/join_dependency_extensions'
|
@@ -30,6 +30,24 @@ module Squeel
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
def where_unscoping(target_value)
|
34
|
+
target_value = target_value.to_s
|
35
|
+
|
36
|
+
where_values.reject! do |rel|
|
37
|
+
case rel
|
38
|
+
when Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual
|
39
|
+
subrelation = (rel.left.kind_of?(Arel::Attributes::Attribute) ? rel.left : rel.right)
|
40
|
+
subrelation.name == target_value
|
41
|
+
when Hash
|
42
|
+
rel.stringify_keys.has_key?(target_value)
|
43
|
+
when Squeel::Nodes::Predicate
|
44
|
+
rel.expr.symbol.to_s == target_value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
bind_values.reject! { |col,_| col.name == target_value }
|
49
|
+
end
|
50
|
+
|
33
51
|
def build_arel
|
34
52
|
arel = Arel::SelectManager.new(table.engine, table)
|
35
53
|
|
@@ -52,9 +70,49 @@ module Squeel
|
|
52
70
|
arel.from(build_from) if from_value
|
53
71
|
arel.lock(lock_value) if lock_value
|
54
72
|
|
73
|
+
# Reorder bind indexes when joins or subqueries include more bindings.
|
74
|
+
# Special for PostgreSQL
|
75
|
+
if bind_values.size > 1
|
76
|
+
bvs = bind_values
|
77
|
+
arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
|
78
|
+
column = bvs[i].first
|
79
|
+
bp.replace connection.substitute_at(column, i)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
55
83
|
arel
|
56
84
|
end
|
57
85
|
|
86
|
+
def build_where(opts, other = [])
|
87
|
+
case opts
|
88
|
+
when String, Array
|
89
|
+
super
|
90
|
+
else # Let's prevent PredicateBuilder from doing its thing
|
91
|
+
[opts, *other].map do |arg|
|
92
|
+
case arg
|
93
|
+
when Array # Just in case there's an array in there somewhere
|
94
|
+
@klass.send(:sanitize_sql, arg)
|
95
|
+
when Hash
|
96
|
+
attributes = @klass.send(:expand_hash_conditions_for_aggregates, arg)
|
97
|
+
|
98
|
+
attributes.values.grep(::ActiveRecord::Relation) do |rel|
|
99
|
+
self.bind_values += rel.bind_values
|
100
|
+
end
|
101
|
+
|
102
|
+
preprocess_attrs_with_ar(attributes)
|
103
|
+
|
104
|
+
when Squeel::Nodes::Node
|
105
|
+
arg.grep(::ActiveRecord::Relation) do |rel|
|
106
|
+
self.bind_values += rel.bind_values
|
107
|
+
end
|
108
|
+
arg
|
109
|
+
else
|
110
|
+
arg
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
58
116
|
def build_from
|
59
117
|
opts, name = from_visit(from_value)
|
60
118
|
case opts
|
@@ -109,6 +167,40 @@ module Squeel
|
|
109
167
|
self
|
110
168
|
end
|
111
169
|
|
170
|
+
def where_values_hash_with_squeel(relation_table_name = table_name)
|
171
|
+
equalities = find_equality_predicates(where_visit(with_default_scope.where_values), relation_table_name)
|
172
|
+
|
173
|
+
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
|
174
|
+
|
175
|
+
Hash[equalities.map { |where|
|
176
|
+
name = where.left.name
|
177
|
+
[name, binds.fetch(name.to_s) { where.right }]
|
178
|
+
}]
|
179
|
+
end
|
180
|
+
|
181
|
+
def to_sql_with_binding_params
|
182
|
+
@to_sql ||= begin
|
183
|
+
relation = self
|
184
|
+
connection = klass.connection
|
185
|
+
|
186
|
+
if eager_loading?
|
187
|
+
find_with_associations { |rel| relation = rel }
|
188
|
+
end
|
189
|
+
|
190
|
+
ast = relation.arel.ast
|
191
|
+
binds = relation.bind_values.dup
|
192
|
+
|
193
|
+
visitor = connection.visitor.clone
|
194
|
+
visitor.class_eval do
|
195
|
+
include ::Arel::Visitors::BindVisitor
|
196
|
+
end
|
197
|
+
|
198
|
+
visitor.accept(ast) do
|
199
|
+
connection.quote(*binds.shift.reverse)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
112
204
|
private
|
113
205
|
|
114
206
|
def dehashified_order_values
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'squeel/adapters/active_record/compat'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Associations
|
5
|
+
class AssociationScope
|
6
|
+
def eval_scope(klass, scope, owner)
|
7
|
+
if scope.is_a?(Relation)
|
8
|
+
scope
|
9
|
+
else
|
10
|
+
klass.unscoped.instance_exec(owner, &scope).visited
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'squeel/adapters/active_record/context'
|
2
|
+
|
3
|
+
module Squeel
|
4
|
+
module Adapters
|
5
|
+
module ActiveRecord
|
6
|
+
class Context < ::Squeel::Context
|
7
|
+
class NoParentFoundError < RuntimeError; end
|
8
|
+
|
9
|
+
def initialize(object)
|
10
|
+
super
|
11
|
+
@base = object.join_root
|
12
|
+
@engine = @base.base_klass.arel_engine
|
13
|
+
@arel_visitor = get_arel_visitor
|
14
|
+
@default_table = Arel::Table.new(@base.table_name, :as => @base.aliased_table_name, :engine => @engine)
|
15
|
+
end
|
16
|
+
|
17
|
+
def find(object, parent = @base)
|
18
|
+
if ::ActiveRecord::Associations::JoinDependency::JoinPart === parent
|
19
|
+
case object
|
20
|
+
when String, Symbol, Nodes::Stub
|
21
|
+
assoc_name = object.to_s
|
22
|
+
find_string_symbol_stub_association(@base.children, @base, assoc_name, parent)
|
23
|
+
when Nodes::Join
|
24
|
+
find_node_join_association(@base.children, @base, object, parent)
|
25
|
+
else
|
26
|
+
find_other_association(@base.children, @base, object, parent)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def find!(object, parent = @base)
|
32
|
+
if ::ActiveRecord::Associations::JoinDependency::JoinPart === parent
|
33
|
+
result =
|
34
|
+
case object
|
35
|
+
when String, Symbol, Nodes::Stub
|
36
|
+
assoc_name = object.to_s
|
37
|
+
find_string_symbol_stub_association(@base.children, @base, assoc_name, parent)
|
38
|
+
when Nodes::Join
|
39
|
+
find_node_join_association(@base.children, @base, object, parent)
|
40
|
+
else
|
41
|
+
find_other_association(@base.children, @base, object, parent)
|
42
|
+
end
|
43
|
+
|
44
|
+
result || raise(NoParentFoundError, "can't find #{object} in #{parent}")
|
45
|
+
else
|
46
|
+
raise NoParentFoundError, "can't find #{object} in #{parent}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def traverse!(keypath, parent = @base, include_endpoint = false)
|
51
|
+
parent = @base if keypath.absolute?
|
52
|
+
keypath.path_without_endpoint.each do |key|
|
53
|
+
parent = find!(key, parent)
|
54
|
+
end
|
55
|
+
parent = find!(keypath.endpoint, parent) if include_endpoint
|
56
|
+
|
57
|
+
parent
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def find_string_symbol_stub_association(join_associations, current_parent, assoc_name, target_parent)
|
62
|
+
join_associations.each do |assoc|
|
63
|
+
return assoc if assoc.reflection.name.to_s == assoc_name && current_parent.equal?(target_parent)
|
64
|
+
child_assoc = find_string_symbol_stub_association(assoc.children, assoc, assoc_name, target_parent)
|
65
|
+
return child_assoc if child_assoc
|
66
|
+
end && false
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_node_join_association(join_associations, current_parent, object, target_parent)
|
70
|
+
join_associations.each do |assoc|
|
71
|
+
return assoc if assoc.reflection.name == object._name && current_parent.equal?(target_parent) &&
|
72
|
+
(object.polymorphic? ? assoc.reflection.klass == object._klass : true)
|
73
|
+
child_assoc = find_node_join_association(assoc.children, assoc, object, target_parent)
|
74
|
+
return child_assoc if child_assoc
|
75
|
+
end && false
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_other_association(join_associations, current_parent, object, target_parent)
|
79
|
+
join_associations.each do |assoc|
|
80
|
+
return assoc if assoc.reflection == object && current_parent.equal?(target_parent)
|
81
|
+
child_assoc = find_other_association(assoc.children, assoc, object, target_parent)
|
82
|
+
return child_assoc if child_assoc
|
83
|
+
end && false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|