Skip to content
This repository has been archived by the owner on Mar 30, 2022. It is now read-only.

Commit

Permalink
Properly append binds from subqueries and associations with PostgreSQL.
Browse files Browse the repository at this point in the history
The issue happens if there are more than 1 bind in the SQL. Fixes #272.

Generate table names correctly when joining throught an association.
Fixes #302.

add mysql, mysql2, postgresql adapter to specs. It should make sure
that Squeel would run against all these databases consistently.

Extend travis scripts to support multiple adapters.
  • Loading branch information
bigxiang committed Jul 18, 2014
1 parent 0782715 commit 321aed1
Show file tree
Hide file tree
Showing 17 changed files with 407 additions and 197 deletions.
39 changes: 33 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
before_script:
- mysql -e "create database squeel_test_examples;"
- psql -c "create database squeel_test_examples;" -U postgres

script:
- bundle exec rake test:$ADAPTER

rvm:
- 1.9.3
- 2.0.0
- 2.1.1
- 2.1.2

env:
- RAILS=master AREL=master
- RAILS=4-1-stable AREL=5-0-stable
- RAILS=4-0-stable AREL=4-0-stable
- RAILS=3-2-stable AREL=3-0-stable
- RAILS=3-1-stable AREL=2-2-stable
- RAILS=3-0-stable AREL=2-0-stable
global:
- SQ_CONFIG_FILE=$TRAVIS_BUILD_DIR/spec/config.travis.yml
matrix:
- RAILS=master AREL=master ADAPTER=sqlite3
- RAILS=4-1-stable AREL=5-0-stable ADAPTER=sqlite3
- RAILS=4-0-stable AREL=4-0-stable ADAPTER=sqlite3
- RAILS=3-2-stable AREL=3-0-stable ADAPTER=sqlite3
- RAILS=3-1-stable AREL=2-2-stable ADAPTER=sqlite3
- RAILS=3-0-stable AREL=2-0-stable ADAPTER=sqlite3
- RAILS=master AREL=master ADAPTER=mysql
- RAILS=4-1-stable AREL=5-0-stable ADAPTER=mysql
- RAILS=4-0-stable AREL=4-0-stable ADAPTER=mysql
- RAILS=3-2-stable AREL=3-0-stable ADAPTER=mysql
- RAILS=3-1-stable AREL=2-2-stable ADAPTER=mysql
- RAILS=3-0-stable AREL=2-0-stable ADAPTER=mysql
- RAILS=master AREL=master ADAPTER=mysql2
- RAILS=4-1-stable AREL=5-0-stable ADAPTER=mysql2
- RAILS=4-0-stable AREL=4-0-stable ADAPTER=mysql2
- RAILS=3-2-stable AREL=3-0-stable ADAPTER=mysql2
- RAILS=3-1-stable AREL=2-2-stable ADAPTER=mysql2
- RAILS=master AREL=master ADAPTER=postgresql
- RAILS=4-1-stable AREL=5-0-stable ADAPTER=postgresql
- RAILS=4-0-stable AREL=4-0-stable ADAPTER=postgresql
- RAILS=3-2-stable AREL=3-0-stable ADAPTER=postgresql
- RAILS=3-1-stable AREL=2-2-stable ADAPTER=postgresql
- RAILS=3-0-stable AREL=2-0-stable ADAPTER=postgresql
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
## 1.2.1 (Unreleased)

* Run all specs against sqlite, mysql and postgresql!
* Genereta table names correctly when joining through an association. Fixes#302.
* Enable Arel nodes in Squeel with "|" operator. Fixes #314.
* Properly append binds from a relation used in a subquery. Fixes #272.
* Use the correct attribute name when finding a Join node. Fixes #273.

## 1.2.0 (2014-07-16)

* Add compatibility to Ruby 2.0+ with Rails 4.1 and 4.2.0.alpha.
Fixes #301, #305, #307
* Enable using a relation as a subquery. Fixes #309
* Bind params correctly in subquery using associations. Fixes #312
* Use the correct attribute name when finding a Join node. Fixes #273.

## 1.1.1 (2013-09-03)

Expand Down
2 changes: 0 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,3 @@ else
gem 'activerecord'
end
end

gem 'polyamorous', git: 'git://github.com/activerecord-hackery/polyamorous.git'
14 changes: 13 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,19 @@ RSpec::Core::RakeTask.new(:spec) do |rspec|
rspec.rspec_opts = ['--backtrace', '--color', '--format documentation']
end

task :default => :spec
task :default => 'test_sqlite3'

%w(sqlite3 mysql mysql2 postgresql).each do |adapter|
namespace :test do
task(adapter => ["#{adapter}:env", "spec"])
end

namespace adapter do
task(:env) { ENV['SQ_DB'] = adapter }
end

task "test_#{adapter}" => ["#{adapter}:env", "test:#{adapter}"]
end

desc "Open an irb session with Squeel and the sample data used in specs"
task :console do
Expand Down
21 changes: 14 additions & 7 deletions lib/squeel/adapters/active_record/4.0/relation_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ def build_arel
arel.from(build_from) if from_value
arel.lock(lock_value) if lock_value

# Reorder bind indexes when joins or subqueries include more bindings.
# Special for PostgreSQL
if bind_values.size > 1
bvs = bind_values
arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
column = bvs[i].first
bp.replace connection.substitute_at(column, i)
end
end

arel
end

Expand All @@ -83,16 +93,13 @@ def build_where(opts, other = [])
when Array # Just in case there's an array in there somewhere
@klass.send(:sanitize_sql, arg)
when Hash
attrs = @klass.send(:expand_hash_conditions_for_aggregates, arg)
attrs.values.grep(::ActiveRecord::Relation) do |rel|
attributes = @klass.send(:expand_hash_conditions_for_aggregates, arg)

attributes.values.grep(::ActiveRecord::Relation) do |rel|
self.bind_values += rel.bind_values
end

unless attrs.keys.grep(Squeel::Nodes::Node).empty? && attrs.keys.grep(Symbol).empty?
attrs
else
super
end
preprocess_attrs_with_ar(attributes)

when Squeel::Nodes::Node
arg.grep(::ActiveRecord::Relation) do |rel|
Expand Down
35 changes: 24 additions & 11 deletions lib/squeel/adapters/active_record/4.1/relation_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ def build_arel
arel.from(build_from) if from_value
arel.lock(lock_value) if lock_value

# Reorder bind indexes when joins or subqueries include more bindings.
# Special for PostgreSQL
if arel.bind_values.any? || bind_values.size > 1
bvs = arel.bind_values + bind_values
arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
column = bvs[i].first
bp.replace connection.substitute_at(column, i)
end
end

arel
end

Expand Down Expand Up @@ -181,19 +191,11 @@ def build_where(opts, other = [])
[opts, *other].map do |arg|
case arg
when Array # Just in case there's an array in there somewhere
@klass.send(:sanitize_sql, arg)
super
when Hash
attrs = @klass.send(:expand_hash_conditions_for_aggregates, arg)
attrs.values.grep(::ActiveRecord::Relation) do |rel|
self.bind_values += rel.bind_values
end

unless attrs.keys.grep(Squeel::Nodes::Node).empty? && attrs.keys.grep(Symbol).empty?
attrs
else
super
end
attributes = expand_attrs_from_hash(arg)

preprocess_attrs_with_ar(attributes)
when Squeel::Nodes::Node
arg.grep(::ActiveRecord::Relation) do |rel|
self.bind_values += rel.bind_values
Expand Down Expand Up @@ -268,6 +270,17 @@ def to_sql_with_binding_params

private

def expand_attrs_from_hash(opts)
opts = ::ActiveRecord::PredicateBuilder.resolve_column_aliases(klass, opts)
attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)

attributes.values.grep(::ActiveRecord::Relation) do |rel|
self.bind_values += rel.bind_values
end

attributes
end

def dehashified_order_values
order_values.map { |o|
if Hash === o && o.values.all? { |v| [:asc, :desc].include?(v) }
Expand Down
49 changes: 15 additions & 34 deletions lib/squeel/adapters/active_record/4.2/relation_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,6 @@ def reverse_order!
self
end

def build_arel
arel = Arel::SelectManager.new(table.engine, table)

build_joins(arel, joins_values.flatten) unless joins_values.empty? && includes_values.empty?

collapse_wheres(arel, where_visit((where_values - ['']).uniq)) #TODO: Add uniq with real value comparison / ignore uniqs that have binds

arel.having(*having_visit(having_values.uniq.reject{|h| h.blank?})) unless having_values.empty?

arel.take(connection.sanitize_limit(limit_value)) if limit_value
arel.skip(offset_value.to_i) if offset_value

arel.group(*group_visit(group_values.uniq.reject{|g| g.blank?})) unless group_values.empty?

build_order(arel)

build_select(arel, select_visit(select_values.uniq))

arel.distinct(distinct_value)
arel.from(build_from) if from_value
arel.lock(lock_value) if lock_value

# Reorder bind indexes if joins produced bind values
if arel.bind_values.any?
bvs = arel.bind_values + bind_values
arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
column = bvs[i].first
bp.replace connection.substitute_at(column, i)
end
end

arel
end

def build_join_dependency(manager, joins)
buckets = joins.group_by do |join|
case join
Expand Down Expand Up @@ -119,6 +85,21 @@ def where_values_hash_with_squeel(relation_table_name = table_name)
}]
}]
end

def expand_attrs_from_hash(opts)
opts = ::ActiveRecord::PredicateBuilder.resolve_column_aliases(klass, opts)

bv_len = bind_values.length
tmp_opts, bind_values = create_binds(opts, bv_len)
self.bind_values += bind_values

attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts)
attributes.values.grep(::ActiveRecord::Relation) do |rel|
self.bind_values += rel.bind_values
end

attributes
end
end
end
end
Expand Down
17 changes: 17 additions & 0 deletions lib/squeel/adapters/active_record/relation_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,23 @@ def build_join_from_subquery(subquery_joins)
end
end

def preprocess_attrs_with_ar(attributes)
attributes.map do |key, value|
case key
when Squeel::Nodes::Node
{key => value}
when Symbol
if value.is_a?(Hash)
{key => value}
else
::ActiveRecord::PredicateBuilder.build_from_hash(klass, {key => value}, table)
end
else
::ActiveRecord::PredicateBuilder.build_from_hash(klass, {key => value}, table)
end
end
end

end
end
end
Expand Down
13 changes: 13 additions & 0 deletions spec/config.travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
databases:
mysql:
database: squeel_test_examples
username: travis
encoding: utf8
mysql2:
database: squeel_test_examples
username: travis
encoding: utf8
postgresql:
database: squeel_test_examples
min_messages: warning
username: postgres
12 changes: 12 additions & 0 deletions spec/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
databases:
mysql:
database: squeel_test_examples
username: squeel
encoding: utf8
mysql2:
database: squeel_test_examples
username: squeel
encoding: utf8
postgresql:
database: squeel_test_examples
min_messages: warning
Loading

0 comments on commit 321aed1

Please sign in to comment.