aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.autotest26
-rw-r--r--.gemtest0
-rw-r--r--.travis.yml24
-rw-r--r--CONTRIBUTING.md100
-rw-r--r--Gemfile11
-rw-r--r--History.txt2
-rw-r--r--MIT-LICENSE.txt3
-rw-r--r--Manifest.txt135
-rw-r--r--README.markdown12
-rw-r--r--Rakefile39
-rw-r--r--arel.gemspec51
-rw-r--r--arel.gemspec.erb25
-rw-r--r--lib/arel.rb2
-rw-r--r--lib/arel/attributes/attribute.rb8
-rw-r--r--lib/arel/collectors/sql_string.rb8
-rw-r--r--lib/arel/crud.rb7
-rw-r--r--lib/arel/delete_manager.rb7
-rw-r--r--lib/arel/insert_manager.rb2
-rw-r--r--lib/arel/nodes.rb41
-rw-r--r--lib/arel/nodes/binary.rb4
-rw-r--r--lib/arel/nodes/bind_param.rb9
-rw-r--r--lib/arel/nodes/casted.rb40
-rw-r--r--lib/arel/nodes/delete_statement.rb2
-rw-r--r--lib/arel/nodes/function.rb1
-rw-r--r--lib/arel/nodes/matches.rb4
-rw-r--r--lib/arel/nodes/regexp.rb14
-rw-r--r--lib/arel/nodes/select_core.rb10
-rw-r--r--lib/arel/nodes/sql_literal.rb3
-rw-r--r--lib/arel/nodes/table_alias.rb8
-rw-r--r--lib/arel/nodes/unary.rb1
-rw-r--r--lib/arel/predications.rb152
-rw-r--r--lib/arel/select_manager.rb18
-rw-r--r--lib/arel/table.rb87
-rw-r--r--lib/arel/tree_manager.rb11
-rw-r--r--lib/arel/update_manager.rb2
-rw-r--r--lib/arel/visitors.rb1
-rw-r--r--lib/arel/visitors/depth_first.rb8
-rw-r--r--lib/arel/visitors/informix.rb7
-rw-r--r--lib/arel/visitors/mssql.rb38
-rw-r--r--lib/arel/visitors/mysql.rb2
-rw-r--r--lib/arel/visitors/oracle.rb6
-rw-r--r--lib/arel/visitors/oracle12.rb53
-rw-r--r--lib/arel/visitors/postgresql.rb28
-rw-r--r--lib/arel/visitors/reduce.rb8
-rw-r--r--lib/arel/visitors/to_sql.rb79
-rw-r--r--lib/arel/visitors/visitor.rb30
-rw-r--r--test/attributes/test_attribute.rb290
-rw-r--r--test/collectors/test_bind_collector.rb10
-rw-r--r--test/collectors/test_sql_string.rb4
-rw-r--r--test/helper.rb2
-rw-r--r--test/nodes/test_binary.rb26
-rw-r--r--test/nodes/test_bind_param.rb15
-rw-r--r--test/nodes/test_select_core.rb8
-rw-r--r--test/nodes/test_sql_literal.rb2
-rw-r--r--test/nodes/test_sum.rb9
-rw-r--r--test/nodes/test_table_alias.rb16
-rw-r--r--test/test_delete_manager.rb18
-rw-r--r--test/test_insert_manager.rb32
-rw-r--r--test/test_select_manager.rb270
-rw-r--r--test/test_table.rb50
-rw-r--r--test/test_update_manager.rb28
-rw-r--r--test/visitors/test_bind_visitor.rb6
-rw-r--r--test/visitors/test_depth_first.rb5
-rw-r--r--test/visitors/test_dot.rb1
-rw-r--r--test/visitors/test_mssql.rb28
-rw-r--r--test/visitors/test_oracle.rb17
-rw-r--r--test/visitors/test_oracle12.rb47
-rw-r--r--test/visitors/test_postgres.rb81
-rw-r--r--test/visitors/test_to_sql.rb64
69 files changed, 1412 insertions, 746 deletions
diff --git a/.autotest b/.autotest
deleted file mode 100644
index 19ea6ecbe6..0000000000
--- a/.autotest
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- ruby -*-
-
-# require 'autotest/restart'
-
-ENV['GEM_PATH'] = "tmp/isolate/ruby-1.8"
-
-module Autotest::Restart
- Autotest.add_hook :updated do |at, *args|
- if args.flatten.include? ".autotest" then
- warn "Detected change to .autotest, restarting"
- cmd = %w(autotest)
- cmd << " -v" if $v
- cmd += ARGV
-
- exec(*cmd)
- end
- end
-end
-
-Autotest.add_hook :initialize do |at|
- at.add_exception 'tmp'
- at.testlib = "minitest/autorun"
-
- at.find_directories = ARGV unless ARGV.empty?
-end
-
diff --git a/.gemtest b/.gemtest
deleted file mode 100644
index e69de29bb2..0000000000
--- a/.gemtest
+++ /dev/null
diff --git a/.travis.yml b/.travis.yml
index 8e5462c440..b8a2f0019e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,18 +1,28 @@
language: ruby
-script:
- - "rake test"
+sudo: false
+cache: bundler
+script:
+ - "bundle exec rake test"
- "gem build arel.gemspec"
+env:
+ global:
+ - JRUBY_OPTS='--dev -J-Xmx1024M'
rvm:
- - rbx
- - jruby
- - 1.9.3
+ - rbx-2
+ - jruby-head
- 2.0.0
- 2.1
+ - 2.2
- ruby-head
matrix:
- allow_failures:
- - rvm: rbx
+ fast_finish: true
+bundler_args: --jobs 3 --retry 3
notifications:
email: false
irc:
- "irc.freenode.org#rails-contrib"
+ campfire:
+ on_success: change
+ on_failure: always
+ rooms:
+ - secure: "sD4VEjsiNHTb+9LYUy0ZiGu86nH1voUANpmiO62fvO1VPg80ReKv8vNiq285MZVjcPBx9lt1iNx1nNfVlBmDzRI1tWjoyEV5LTuCAt3yQMB5Qpjy3HH1FNgyY2TGjDhIDwgTD6d8+DOCQjj/vgqzWWu1jEJVdac1K5d+dc/uElI="
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..104c05490f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,100 @@
+Contributing to Arel
+=====================
+
+[![Build Status](https://secure.travis-ci.org/rails/arel.svg?branch=master)](http://travis-ci.org/rails/arel)
+[![Dependency Status](https://gemnasium.com/rails/arel.svg)](https://gemnasium.com/rails/arel)
+
+Arel is work of [many contributors](https://github.com/rails/arel/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/rails/arel/pulls), [propose features and discuss issues](https://github.com/rails/arel/issues).
+
+#### Fork the Project
+
+Fork the [project on Github](https://github.com/rails/arel) and check out your copy.
+
+```
+git clone https://github.com/contributor/arel.git
+cd arel
+git remote add upstream https://github.com/rails/arel.git
+```
+
+#### Create a Topic Branch
+
+Make sure your fork is up-to-date and create a topic branch for your feature or bug fix.
+
+```
+git checkout master
+git pull upstream master
+git checkout -b my-feature-branch
+```
+
+#### Bundle Install and Test
+
+Ensure that you can build the project and run tests.
+
+```
+bundle install
+bundle exec rake test
+```
+
+#### Write Tests
+
+Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [test](test).
+
+We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix.
+
+#### Write Code
+
+Implement your feature or bug fix.
+
+Make sure that `bundle exec rake test` completes without errors.
+
+#### Write Documentation
+
+Document any external behavior in the [README](README.md).
+
+#### Commit Changes
+
+Make sure git knows your name and email address:
+
+```
+git config --global user.name "Your Name"
+git config --global user.email "contributor@example.com"
+```
+
+Writing good commit logs is important. A commit log should describe what changed and why.
+
+```
+git add ...
+git commit
+```
+
+#### Push
+
+```
+git push origin my-feature-branch
+```
+
+#### Make a Pull Request
+
+Go to https://github.com/contributor/arel and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days.
+
+#### Rebase
+
+If you've been working on a change for a while, rebase with upstream/master.
+
+```
+git fetch upstream
+git rebase upstream/master
+git push origin my-feature-branch -f
+```
+
+#### Check on Your Pull Request
+
+Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
+
+#### Be Patient
+
+It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there!
+
+#### Thank You
+
+Please do know that we really appreciate and value your time and work. We love you, really.
diff --git a/Gemfile b/Gemfile
index 12c57d3737..07483b27d3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,12 +1,3 @@
-# -*- ruby -*-
-
-# DO NOT EDIT THIS FILE. Instead, edit Rakefile, and run `rake bundler:gemfile`.
-
source "https://rubygems.org/"
-
-gem "minitest", "~>5.1", :group => [:development, :test]
-gem "rdoc", "~>4.0", :group => [:development, :test]
-gem "hoe", "~>3.5", :group => [:development, :test]
-
-# vim: syntax=ruby
+gemspec
diff --git a/History.txt b/History.txt
index 4fc06816a3..b161f5ca19 100644
--- a/History.txt
+++ b/History.txt
@@ -1,4 +1,4 @@
-=== NEXT / 2014-02-10
+=== 6.0.0 / 2014-11-25
* Enhancements
diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt
index 52f1ff7a17..001426b5b0 100644
--- a/MIT-LICENSE.txt
+++ b/MIT-LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright (c) 2007-2010 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
+Copyright (c) 2007-2015 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -18,3 +18,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/Manifest.txt b/Manifest.txt
deleted file mode 100644
index 32e1dd43a6..0000000000
--- a/Manifest.txt
+++ /dev/null
@@ -1,135 +0,0 @@
-.autotest
-.gemtest
-.travis.yml
-Gemfile
-History.txt
-MIT-LICENSE.txt
-Manifest.txt
-README.markdown
-Rakefile
-arel.gemspec
-lib/arel.rb
-lib/arel/alias_predication.rb
-lib/arel/attributes.rb
-lib/arel/attributes/attribute.rb
-lib/arel/collectors/bind.rb
-lib/arel/collectors/plain_string.rb
-lib/arel/collectors/sql_string.rb
-lib/arel/compatibility/wheres.rb
-lib/arel/crud.rb
-lib/arel/delete_manager.rb
-lib/arel/expressions.rb
-lib/arel/factory_methods.rb
-lib/arel/insert_manager.rb
-lib/arel/math.rb
-lib/arel/nodes.rb
-lib/arel/nodes/and.rb
-lib/arel/nodes/ascending.rb
-lib/arel/nodes/binary.rb
-lib/arel/nodes/count.rb
-lib/arel/nodes/delete_statement.rb
-lib/arel/nodes/descending.rb
-lib/arel/nodes/equality.rb
-lib/arel/nodes/extract.rb
-lib/arel/nodes/false.rb
-lib/arel/nodes/full_outer_join.rb
-lib/arel/nodes/function.rb
-lib/arel/nodes/grouping.rb
-lib/arel/nodes/in.rb
-lib/arel/nodes/infix_operation.rb
-lib/arel/nodes/inner_join.rb
-lib/arel/nodes/insert_statement.rb
-lib/arel/nodes/join_source.rb
-lib/arel/nodes/named_function.rb
-lib/arel/nodes/node.rb
-lib/arel/nodes/outer_join.rb
-lib/arel/nodes/over.rb
-lib/arel/nodes/right_outer_join.rb
-lib/arel/nodes/select_core.rb
-lib/arel/nodes/select_statement.rb
-lib/arel/nodes/sql_literal.rb
-lib/arel/nodes/string_join.rb
-lib/arel/nodes/table_alias.rb
-lib/arel/nodes/terminal.rb
-lib/arel/nodes/true.rb
-lib/arel/nodes/unary.rb
-lib/arel/nodes/unqualified_column.rb
-lib/arel/nodes/update_statement.rb
-lib/arel/nodes/values.rb
-lib/arel/nodes/window.rb
-lib/arel/nodes/with.rb
-lib/arel/order_predications.rb
-lib/arel/predications.rb
-lib/arel/select_manager.rb
-lib/arel/table.rb
-lib/arel/tree_manager.rb
-lib/arel/update_manager.rb
-lib/arel/visitors.rb
-lib/arel/visitors/bind_substitute.rb
-lib/arel/visitors/bind_visitor.rb
-lib/arel/visitors/depth_first.rb
-lib/arel/visitors/dot.rb
-lib/arel/visitors/ibm_db.rb
-lib/arel/visitors/informix.rb
-lib/arel/visitors/mssql.rb
-lib/arel/visitors/mysql.rb
-lib/arel/visitors/oracle.rb
-lib/arel/visitors/postgresql.rb
-lib/arel/visitors/reduce.rb
-lib/arel/visitors/sqlite.rb
-lib/arel/visitors/to_sql.rb
-lib/arel/visitors/visitor.rb
-lib/arel/visitors/where_sql.rb
-lib/arel/window_predications.rb
-test/attributes/test_attribute.rb
-test/collectors/test_bind_collector.rb
-test/collectors/test_sql_string.rb
-test/helper.rb
-test/nodes/test_and.rb
-test/nodes/test_as.rb
-test/nodes/test_ascending.rb
-test/nodes/test_bin.rb
-test/nodes/test_count.rb
-test/nodes/test_delete_statement.rb
-test/nodes/test_descending.rb
-test/nodes/test_distinct.rb
-test/nodes/test_equality.rb
-test/nodes/test_extract.rb
-test/nodes/test_false.rb
-test/nodes/test_grouping.rb
-test/nodes/test_infix_operation.rb
-test/nodes/test_insert_statement.rb
-test/nodes/test_named_function.rb
-test/nodes/test_node.rb
-test/nodes/test_not.rb
-test/nodes/test_or.rb
-test/nodes/test_over.rb
-test/nodes/test_select_core.rb
-test/nodes/test_select_statement.rb
-test/nodes/test_sql_literal.rb
-test/nodes/test_sum.rb
-test/nodes/test_table_alias.rb
-test/nodes/test_true.rb
-test/nodes/test_update_statement.rb
-test/nodes/test_window.rb
-test/support/fake_record.rb
-test/test_attributes.rb
-test/test_crud.rb
-test/test_delete_manager.rb
-test/test_factory_methods.rb
-test/test_insert_manager.rb
-test/test_select_manager.rb
-test/test_table.rb
-test/test_update_manager.rb
-test/visitors/test_bind_visitor.rb
-test/visitors/test_depth_first.rb
-test/visitors/test_dispatch_contamination.rb
-test/visitors/test_dot.rb
-test/visitors/test_ibm_db.rb
-test/visitors/test_informix.rb
-test/visitors/test_mssql.rb
-test/visitors/test_mysql.rb
-test/visitors/test_oracle.rb
-test/visitors/test_postgres.rb
-test/visitors/test_sqlite.rb
-test/visitors/test_to_sql.rb
diff --git a/README.markdown b/README.markdown
index 76efb2b34a..d570f7855c 100644
--- a/README.markdown
+++ b/README.markdown
@@ -1,4 +1,4 @@
-# Arel [![Build Status](https://secure.travis-ci.org/rails/arel.svg?branch=master)](http://travis-ci.org/rails/arel) [![Dependency Status](https://gemnasium.com/rails/arel.svg)](https://gemnasium.com/rails/arel)
+# Arel
* http://github.com/rails/arel
@@ -222,6 +222,12 @@ photos.project(photo_clicks.as("photo_clicks"))
FROM "photos"
```
-### License
+## Contributing to Arel
-Arel is released under the [MIT License](http://opensource.org/licenses/MIT).
+Arel is work of many contributors. You're encouraged to submit pull requests, propose
+features and discuss issues.
+
+See [CONTRIBUTING](CONTRIBUTING.md).
+
+## License
+Arel is released under the [MIT License](http://www.opensource.org/licenses/MIT).
diff --git a/Rakefile b/Rakefile
index f9257d696f..956e95c939 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,20 +1,27 @@
-require "rubygems"
-gem 'hoe', '>= 3.3.1'
-require 'hoe'
+require 'bundler'
+Bundler::GemHelper.install_tasks
-Hoe.plugins.delete :rubyforge
-Hoe.plugin :minitest
-Hoe.plugin :gemspec # `gem install hoe-gemspec`
-Hoe.plugin :git # `gem install hoe-git`
-Hoe.plugin :bundler # `gem install hoe-bundler`
+require 'rake/testtask'
-Hoe.spec 'arel' do
- developer('Aaron Patterson', 'aaron@tenderlovemaking.com')
- developer('Bryan Helmkamp', 'bryan@brynary.com')
- developer('Emilio Tagua', 'miloops@gmail.com')
- developer('Nick Kallen', 'nick@example.org') # FIXME: need Nick's email
+desc "Default Task"
+task default: [ :test ]
- self.licenses = ['MIT']
- self.readme_file = 'README.markdown'
- self.extra_rdoc_files = FileList['README.markdown']
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/test_*.rb'
+ t.verbose = true
+end
+
+specname = "arel.gemspec"
+deps = `git ls-files`.split("\n") - [specname]
+
+file specname => deps do
+ files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] + `git ls-files -- lib`.split("\n")
+
+ require 'erb'
+
+ File.open specname, 'w:utf-8' do |f|
+ f.write ERB.new(File.read("#{specname}.erb")).result(binding)
+ end
end
diff --git a/arel.gemspec b/arel.gemspec
index 832eb12f49..dd52c89e22 100644
--- a/arel.gemspec
+++ b/arel.gemspec
@@ -1,40 +1,25 @@
-# -*- encoding: utf-8 -*-
-# stub: arel 6.0.0.beta1.20140817224534 ruby lib
+# # -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "arel"
Gem::Specification.new do |s|
- s.name = "arel"
- s.version = "6.0.0.beta1.20140817224534"
-
- s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
- s.require_paths = ["lib"]
- s.authors = ["Aaron Patterson", "Bryan Helmkamp", "Emilio Tagua", "Nick Kallen"]
- s.date = "2014-08-18"
+ s.name = "arel"
+ s.version = Arel::VERSION
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["Aaron Patterson", "Bryan Helmkamp", "Emilio Tagua", "Nick Kallen"]
+ s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com"]
+ s.homepage = "https://github.com/rails/arel"
s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation."
- s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"]
- s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"]
- s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/collectors/bind.rb", "lib/arel/collectors/plain_string.rb", "lib/arel/collectors/sql_string.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/expressions.rb", "lib/arel/factory_methods.rb", "lib/arel/insert_manager.rb", "lib/arel/math.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/ascending.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/descending.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/extract.rb", "lib/arel/nodes/false.rb", "lib/arel/nodes/full_outer_join.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/infix_operation.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/over.rb", "lib/arel/nodes/right_outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/window.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/select_manager.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.rb", "lib/arel/visitors/bind_substitute.rb", "lib/arel/visitors/bind_visitor.rb", "lib/arel/visitors/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/ibm_db.rb", "lib/arel/visitors/informix.rb", "lib/arel/visitors/mssql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/reduce.rb", "lib/arel/visitors/sqlite.rb", "lib/arel/visitors/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "lib/arel/window_predications.rb", "test/attributes/test_attribute.rb", "test/collectors/test_bind_collector.rb", "test/collectors/test_sql_string.rb", "test/helper.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/support/fake_record.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"]
- s.homepage = "http://github.com/rails/arel"
- s.licenses = ["MIT"]
+ s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby"
+ s.license = %q{MIT}
+
s.rdoc_options = ["--main", "README.markdown"]
- s.rubygems_version = "2.2.2"
- s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby"
- s.test_files = ["test/attributes/test_attribute.rb", "test/collectors/test_bind_collector.rb", "test/collectors/test_sql_string.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"]
+ s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"]
- if s.respond_to? :specification_version then
- s.specification_version = 4
+ s.files = ["History.txt","MIT-LICENSE.txt","README.markdown","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"]
+ s.require_paths = ["lib"]
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
- s.add_development_dependency(%q<minitest>, ["~> 5.4"])
- s.add_development_dependency(%q<rdoc>, ["~> 4.0"])
- s.add_development_dependency(%q<hoe>, ["~> 3.12"])
- else
- s.add_dependency(%q<minitest>, ["~> 5.4"])
- s.add_dependency(%q<rdoc>, ["~> 4.0"])
- s.add_dependency(%q<hoe>, ["~> 3.12"])
- end
- else
- s.add_dependency(%q<minitest>, ["~> 5.4"])
- s.add_dependency(%q<rdoc>, ["~> 4.0"])
- s.add_dependency(%q<hoe>, ["~> 3.12"])
- end
+ s.add_development_dependency('minitest', '~> 5.4')
+ s.add_development_dependency('rdoc', '~> 4.0')
+ s.add_development_dependency('rake')
end
diff --git a/arel.gemspec.erb b/arel.gemspec.erb
new file mode 100644
index 0000000000..7ed75226ca
--- /dev/null
+++ b/arel.gemspec.erb
@@ -0,0 +1,25 @@
+# # -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "arel"
+
+Gem::Specification.new do |s|
+ s.name = "arel"
+ s.version = Arel::VERSION
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["Aaron Patterson", "Bryan Helmkamp", "Emilio Tagua", "Nick Kallen"]
+ s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com"]
+ s.homepage = "https://github.com/rails/arel"
+ s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation."
+ s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby"
+ s.license = %q{MIT}
+
+ s.rdoc_options = ["--main", "README.markdown"]
+ s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"]
+
+ s.files = [<%= files.map(&:inspect).join ',' %>]
+ s.require_paths = ["lib"]
+
+ s.add_development_dependency('minitest', '~> 5.4')
+ s.add_development_dependency('rdoc', '~> 4.0')
+ s.add_development_dependency('rake')
+end
diff --git a/lib/arel.rb b/lib/arel.rb
index 80677953df..aab93913d5 100644
--- a/lib/arel.rb
+++ b/lib/arel.rb
@@ -21,7 +21,7 @@ require 'arel/delete_manager'
require 'arel/nodes'
module Arel
- VERSION = '6.0.0.beta1'
+ VERSION = '7.0.0.alpha'
def self.sql raw_sql
Arel::Nodes::SqlLiteral.new raw_sql
diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb
index 0906fa4f1d..cda5a5a3db 100644
--- a/lib/arel/attributes/attribute.rb
+++ b/lib/arel/attributes/attribute.rb
@@ -12,6 +12,14 @@ module Arel
def lower
relation.lower self
end
+
+ def type_cast_for_database(value)
+ relation.type_cast_for_database(name, value)
+ end
+
+ def able_to_type_cast?
+ relation.able_to_type_cast?
+ end
end
class String < Attribute; end
diff --git a/lib/arel/collectors/sql_string.rb b/lib/arel/collectors/sql_string.rb
index 8ca89ca7bd..fd2faaef3a 100644
--- a/lib/arel/collectors/sql_string.rb
+++ b/lib/arel/collectors/sql_string.rb
@@ -5,8 +5,14 @@ require 'arel/collectors/plain_string'
module Arel
module Collectors
class SQLString < PlainString
+ def initialize(*)
+ super
+ @bind_index = 1
+ end
+
def add_bind bind
- self << bind.to_s
+ self << yield(@bind_index)
+ @bind_index += 1
self
end
diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb
index 6f4962cbfe..d310c7381f 100644
--- a/lib/arel/crud.rb
+++ b/lib/arel/crud.rb
@@ -3,7 +3,7 @@ module Arel
# FIXME hopefully we can remove this
module Crud
def compile_update values, pk
- um = UpdateManager.new @engine
+ um = UpdateManager.new
if Nodes::SqlLiteral === values
relation = @ctx.from
@@ -26,11 +26,12 @@ module Arel
end
def create_insert
- InsertManager.new @engine
+ InsertManager.new
end
def compile_delete
- dm = DeleteManager.new @engine
+ dm = DeleteManager.new
+ dm.take @ast.limit.expr if @ast.limit
dm.wheres = @ctx.wheres
dm.from @ctx.froms
dm
diff --git a/lib/arel/delete_manager.rb b/lib/arel/delete_manager.rb
index b4c61f708f..20e988e01f 100644
--- a/lib/arel/delete_manager.rb
+++ b/lib/arel/delete_manager.rb
@@ -1,6 +1,6 @@
module Arel
class DeleteManager < Arel::TreeManager
- def initialize engine
+ def initialize
super
@ast = Nodes::DeleteStatement.new
@ctx = @ast
@@ -11,6 +11,11 @@ module Arel
self
end
+ def take limit
+ @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit
+ self
+ end
+
def wheres= list
@ast.wheres = list
end
diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb
index 8839dd8181..7829c3f4f9 100644
--- a/lib/arel/insert_manager.rb
+++ b/lib/arel/insert_manager.rb
@@ -1,6 +1,6 @@
module Arel
class InsertManager < Arel::TreeManager
- def initialize engine
+ def initialize
super
@ast = Nodes::InsertStatement.new
end
diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb
index ccccd471e2..0e66d2dd0c 100644
--- a/lib/arel/nodes.rb
+++ b/lib/arel/nodes.rb
@@ -4,6 +4,7 @@ require 'arel/nodes/select_statement'
require 'arel/nodes/select_core'
require 'arel/nodes/insert_statement'
require 'arel/nodes/update_statement'
+require 'arel/nodes/bind_param'
# terminal
@@ -29,6 +30,7 @@ require 'arel/nodes/table_alias'
require 'arel/nodes/infix_operation'
require 'arel/nodes/over'
require 'arel/nodes/matches'
+require 'arel/nodes/regexp'
# nary
require 'arel/nodes/and'
@@ -54,41 +56,4 @@ require 'arel/nodes/string_join'
require 'arel/nodes/sql_literal'
-module Arel
- module Nodes
- class Casted < Arel::Nodes::Node # :nodoc:
- attr_reader :val, :attribute
- def initialize val, attribute
- @val = val
- @attribute = attribute
- super()
- end
-
- def nil?; @val.nil?; end
-
- def eql? other
- self.class == other.class &&
- self.val == other.val &&
- self.attribute == other.attribute
- end
- alias :== :eql?
- end
-
- class Quoted < Arel::Nodes::Unary # :nodoc:
- end
-
- def self.build_quoted other, attribute = nil
- case other
- when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager
- other
- else
- case attribute
- when Arel::Attributes::Attribute
- Casted.new other, attribute
- else
- Quoted.new other
- end
- end
- end
- end
-end
+require 'arel/nodes/casted'
diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb
index e35d2fd2e7..763091c267 100644
--- a/lib/arel/nodes/binary.rb
+++ b/lib/arel/nodes/binary.rb
@@ -16,7 +16,7 @@ module Arel
end
def hash
- [@left, @right].hash
+ [self.class, @left, @right].hash
end
def eql? other
@@ -38,9 +38,7 @@ module Arel
LessThanOrEqual
NotEqual
NotIn
- NotRegexp
Or
- Regexp
Union
UnionAll
Intersect
diff --git a/lib/arel/nodes/bind_param.rb b/lib/arel/nodes/bind_param.rb
new file mode 100644
index 0000000000..3a4aedc4ba
--- /dev/null
+++ b/lib/arel/nodes/bind_param.rb
@@ -0,0 +1,9 @@
+module Arel
+ module Nodes
+ class BindParam < Node
+ def ==(other)
+ other.is_a?(BindParam)
+ end
+ end
+ end
+end
diff --git a/lib/arel/nodes/casted.rb b/lib/arel/nodes/casted.rb
new file mode 100644
index 0000000000..9fa02955ef
--- /dev/null
+++ b/lib/arel/nodes/casted.rb
@@ -0,0 +1,40 @@
+module Arel
+ module Nodes
+ class Casted < Arel::Nodes::Node # :nodoc:
+ attr_reader :val, :attribute
+ def initialize val, attribute
+ @val = val
+ @attribute = attribute
+ super()
+ end
+
+ def nil?; @val.nil?; end
+
+ def eql? other
+ self.class == other.class &&
+ self.val == other.val &&
+ self.attribute == other.attribute
+ end
+ alias :== :eql?
+ end
+
+ class Quoted < Arel::Nodes::Unary # :nodoc:
+ alias :val :value
+ def nil?; val.nil?; end
+ end
+
+ def self.build_quoted other, attribute = nil
+ case other
+ when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted
+ other
+ else
+ case attribute
+ when Arel::Attributes::Attribute
+ Casted.new other, attribute
+ else
+ Quoted.new other
+ end
+ end
+ end
+ end
+end
diff --git a/lib/arel/nodes/delete_statement.rb b/lib/arel/nodes/delete_statement.rb
index 3bac8225ec..8aaf8ca0b6 100644
--- a/lib/arel/nodes/delete_statement.rb
+++ b/lib/arel/nodes/delete_statement.rb
@@ -1,6 +1,8 @@
module Arel
module Nodes
class DeleteStatement < Arel::Nodes::Binary
+ attr_accessor :limit
+
alias :relation :left
alias :relation= :left=
alias :wheres :right
diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb
index 733a00df46..182dfa7329 100644
--- a/lib/arel/nodes/function.rb
+++ b/lib/arel/nodes/function.rb
@@ -3,6 +3,7 @@ module Arel
class Function < Arel::Nodes::Node
include Arel::Predications
include Arel::WindowPredications
+ include Arel::OrderPredications
attr_accessor :expressions, :alias, :distinct
def initialize expr, aliaz = nil
diff --git a/lib/arel/nodes/matches.rb b/lib/arel/nodes/matches.rb
index 583fb97c9b..0d9c1925dc 100644
--- a/lib/arel/nodes/matches.rb
+++ b/lib/arel/nodes/matches.rb
@@ -2,10 +2,12 @@ module Arel
module Nodes
class Matches < Binary
attr_reader :escape
+ attr_accessor :case_sensitive
- def initialize(left, right, escape = nil)
+ def initialize(left, right, escape = nil, case_sensitive = false)
super(left, right)
@escape = escape && Nodes.build_quoted(escape)
+ @case_sensitive = case_sensitive
end
end
diff --git a/lib/arel/nodes/regexp.rb b/lib/arel/nodes/regexp.rb
new file mode 100644
index 0000000000..784368f5bf
--- /dev/null
+++ b/lib/arel/nodes/regexp.rb
@@ -0,0 +1,14 @@
+module Arel
+ module Nodes
+ class Regexp < Binary
+ attr_accessor :case_sensitive
+
+ def initialize(left, right, case_sensitive = true)
+ super(left, right)
+ @case_sensitive = case_sensitive
+ end
+ end
+
+ class NotRegexp < Regexp; end
+ end
+end
diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb
index 09ae420aa1..3696dd20af 100644
--- a/lib/arel/nodes/select_core.rb
+++ b/lib/arel/nodes/select_core.rb
@@ -2,7 +2,7 @@ module Arel
module Nodes
class SelectCore < Arel::Nodes::Node
attr_accessor :top, :projections, :wheres, :groups, :windows
- attr_accessor :having, :source, :set_quantifier
+ attr_accessor :havings, :source, :set_quantifier
def initialize
super()
@@ -14,7 +14,7 @@ module Arel
@projections = []
@wheres = []
@groups = []
- @having = nil
+ @havings = []
@windows = []
end
@@ -35,14 +35,14 @@ module Arel
@projections = @projections.clone
@wheres = @wheres.clone
@groups = @groups.clone
- @having = @having.clone if @having
+ @havings = @havings.clone
@windows = @windows.clone
end
def hash
[
@source, @top, @set_quantifier, @projections,
- @wheres, @groups, @having, @windows
+ @wheres, @groups, @havings, @windows
].hash
end
@@ -54,7 +54,7 @@ module Arel
self.projections == other.projections &&
self.wheres == other.wheres &&
self.groups == other.groups &&
- self.having == other.having &&
+ self.havings == other.havings &&
self.windows == other.windows
end
alias :== :eql?
diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb
index b43288b29c..2c56644b99 100644
--- a/lib/arel/nodes/sql_literal.rb
+++ b/lib/arel/nodes/sql_literal.rb
@@ -10,8 +10,5 @@ module Arel
coder.scalar = self.to_s
end
end
-
- class BindParam < SqlLiteral
- end
end
end
diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb
index ebfcb58e64..a5adc0766a 100644
--- a/lib/arel/nodes/table_alias.rb
+++ b/lib/arel/nodes/table_alias.rb
@@ -13,8 +13,12 @@ module Arel
relation.respond_to?(:name) ? relation.name : name
end
- def engine
- relation.engine
+ def type_cast_for_database(*args)
+ relation.type_cast_for_database(*args)
+ end
+
+ def able_to_type_cast?
+ relation.respond_to?(:able_to_type_cast?) && relation.able_to_type_cast?
end
end
end
diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb
index 3d4a4b014a..a0062ff5be 100644
--- a/lib/arel/nodes/unary.rb
+++ b/lib/arel/nodes/unary.rb
@@ -23,7 +23,6 @@ module Arel
%w{
Bin
Group
- Having
Limit
Not
Offset
diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb
index 3050526a43..1d2b0de235 100644
--- a/lib/arel/predications.rb
+++ b/lib/arel/predications.rb
@@ -1,7 +1,7 @@
module Arel
module Predications
def not_eq other
- Nodes::NotEqual.new self, Nodes.build_quoted(other, self)
+ Nodes::NotEqual.new self, quoted_node(other)
end
def not_eq_any others
@@ -13,7 +13,7 @@ module Arel
end
def eq other
- Nodes::Equality.new self, Nodes.build_quoted(other, self)
+ Nodes::Equality.new self, quoted_node(other)
end
def eq_any others
@@ -21,7 +21,27 @@ module Arel
end
def eq_all others
- grouping_all :eq, others.map { |x| Nodes.build_quoted(x, self) }
+ grouping_all :eq, quoted_array(others)
+ end
+
+ def between other
+ if equals_quoted?(other.begin, -Float::INFINITY)
+ if equals_quoted?(other.end, Float::INFINITY)
+ not_in([])
+ elsif other.exclude_end?
+ lt(other.end)
+ else
+ lteq(other.end)
+ end
+ elsif equals_quoted?(other.end, Float::INFINITY)
+ gteq(other.begin)
+ elsif other.exclude_end?
+ gteq(other.begin).and(lt(other.end))
+ else
+ left = quoted_node(other.begin)
+ right = quoted_node(other.end)
+ Nodes::Between.new(self, left.and(right))
+ end
end
def in other
@@ -29,27 +49,16 @@ module Arel
when Arel::SelectManager
Arel::Nodes::In.new(self, other.ast)
when Range
- if other.begin == -Float::INFINITY
- if other.end == Float::INFINITY
- Nodes::NotIn.new self, []
- elsif other.exclude_end?
- Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self))
- else
- Nodes::LessThanOrEqual.new(self, Nodes.build_quoted(other.end, self))
- end
- elsif other.end == Float::INFINITY
- Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.begin, self))
- elsif other.exclude_end?
- left = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.begin, self))
- right = Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self))
- Nodes::And.new [left, right]
- else
- Nodes::Between.new(self, Nodes::And.new([Nodes.build_quoted(other.begin, self), Nodes.build_quoted(other.end, self)]))
+ if $VERBOSE
+ warn <<-eowarn
+Passing a range to `#in` is deprecated. Call `#between`, instead.
+ eowarn
end
- when Array
- Nodes::In.new self, other.map { |x| Nodes.build_quoted(x, self) }
+ between(other)
+ when Enumerable
+ Nodes::In.new self, quoted_array(other)
else
- Nodes::In.new self, Nodes.build_quoted(other, self)
+ Nodes::In.new self, quoted_node(other)
end
end
@@ -61,34 +70,43 @@ module Arel
grouping_all :in, others
end
+ def not_between other
+ if equals_quoted?(other.begin, -Float::INFINITY)
+ if equals_quoted?(other.end, Float::INFINITY)
+ self.in([])
+ elsif other.exclude_end?
+ gteq(other.end)
+ else
+ gt(other.end)
+ end
+ elsif equals_quoted?(other.end, Float::INFINITY)
+ lt(other.begin)
+ else
+ left = lt(other.begin)
+ right = if other.exclude_end?
+ gteq(other.end)
+ else
+ gt(other.end)
+ end
+ left.or(right)
+ end
+ end
+
def not_in other
case other
when Arel::SelectManager
Arel::Nodes::NotIn.new(self, other.ast)
when Range
- if other.begin == -Float::INFINITY # The range begins with negative infinity
- if other.end == Float::INFINITY
- Nodes::In.new self, [] # The range is infinite, so return an empty range
- elsif other.exclude_end?
- Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self))
- else
- Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self))
- end
- elsif other.end == Float::INFINITY
- Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self))
- else
- left = Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self))
- if other.exclude_end?
- right = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self))
- else
- right = Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self))
- end
- Nodes::Or.new left, right
+ if $VERBOSE
+ warn <<-eowarn
+Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
+ eowarn
end
- when Array
- Nodes::NotIn.new self, other.map { |x| Nodes.build_quoted(x, self) }
+ not_between(other)
+ when Enumerable
+ Nodes::NotIn.new self, quoted_array(other)
else
- Nodes::NotIn.new self, Nodes.build_quoted(other, self)
+ Nodes::NotIn.new self, quoted_node(other)
end
end
@@ -100,20 +118,28 @@ module Arel
grouping_all :not_in, others
end
- def matches other, escape = nil
- Nodes::Matches.new self, Nodes.build_quoted(other, self), escape
+ def matches other, escape = nil, case_sensitive = false
+ Nodes::Matches.new self, quoted_node(other), escape, case_sensitive
+ end
+
+ def matches_regexp other, case_sensitive = true
+ Nodes::Regexp.new self, quoted_node(other), case_sensitive
+ end
+
+ def matches_any others, escape = nil, case_sensitive = false
+ grouping_any :matches, others, escape, case_sensitive
end
- def matches_any others, escape = nil
- grouping_any :matches, others, escape
+ def matches_all others, escape = nil, case_sensitive = false
+ grouping_all :matches, others, escape, case_sensitive
end
- def matches_all others, escape = nil
- grouping_all :matches, others, escape
+ def does_not_match other, escape = nil, case_sensitive = false
+ Nodes::DoesNotMatch.new self, quoted_node(other), escape, case_sensitive
end
- def does_not_match other, escape = nil
- Nodes::DoesNotMatch.new self, Nodes.build_quoted(other, self), escape
+ def does_not_match_regexp other, case_sensitive = true
+ Nodes::NotRegexp.new self, quoted_node(other), case_sensitive
end
def does_not_match_any others, escape = nil
@@ -125,7 +151,7 @@ module Arel
end
def gteq right
- Nodes::GreaterThanOrEqual.new self, Nodes.build_quoted(right, self)
+ Nodes::GreaterThanOrEqual.new self, quoted_node(right)
end
def gteq_any others
@@ -137,7 +163,7 @@ module Arel
end
def gt right
- Nodes::GreaterThan.new self, Nodes.build_quoted(right, self)
+ Nodes::GreaterThan.new self, quoted_node(right)
end
def gt_any others
@@ -149,7 +175,7 @@ module Arel
end
def lt right
- Nodes::LessThan.new self, Nodes.build_quoted(right, self)
+ Nodes::LessThan.new self, quoted_node(right)
end
def lt_any others
@@ -161,7 +187,7 @@ module Arel
end
def lteq right
- Nodes::LessThanOrEqual.new self, Nodes.build_quoted(right, self)
+ Nodes::LessThanOrEqual.new self, quoted_node(right)
end
def lteq_any others
@@ -185,5 +211,21 @@ module Arel
nodes = others.map {|expr| send(method_id, expr, *extras)}
Nodes::Grouping.new Nodes::And.new(nodes)
end
+
+ def quoted_node(other)
+ Nodes.build_quoted(other, self)
+ end
+
+ def quoted_array(others)
+ others.map { |v| quoted_node(v) }
+ end
+
+ def equals_quoted?(maybe_quoted, value)
+ if maybe_quoted.is_a?(Nodes::Quoted)
+ maybe_quoted.val == value
+ else
+ maybe_quoted == value
+ end
+ end
end
end
diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb
index 5a05e7e181..f7dec87ca3 100644
--- a/lib/arel/select_manager.rb
+++ b/lib/arel/select_manager.rb
@@ -6,8 +6,8 @@ module Arel
STRING_OR_SYMBOL_CLASS = [Symbol, String]
- def initialize engine, table = nil
- super(engine)
+ def initialize table = nil
+ super()
@ast = Nodes::SelectStatement.new
@ctx = @ast.cores.last
from table
@@ -19,7 +19,7 @@ module Arel
end
def limit
- @ast.limit && @ast.limit.expr.expr
+ @ast.limit && @ast.limit.expr
end
alias :taken :limit
@@ -118,8 +118,8 @@ module Arel
join(relation, Nodes::OuterJoin)
end
- def having *exprs
- @ctx.having = Nodes::Having.new(collapse(exprs, @ctx.having))
+ def having expr
+ @ctx.havings << expr
self
end
@@ -176,10 +176,10 @@ module Arel
@ast.orders
end
- def where_sql
+ def where_sql engine = Table.engine
return if @ctx.wheres.empty?
- viz = Visitors::WhereSql.new @engine.connection
+ viz = Visitors::WhereSql.new engine.connection
Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value
end
@@ -216,8 +216,8 @@ module Arel
def take limit
if limit
- @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit))
- @ctx.top = Nodes::Top.new(Nodes.build_quoted(limit))
+ @ast.limit = Nodes::Limit.new(limit)
+ @ctx.top = Nodes::Top.new(limit)
else
@ast.limit = nil
@ctx.top = nil
diff --git a/lib/arel/table.rb b/lib/arel/table.rb
index 01d4561ff1..b4b4a861b8 100644
--- a/lib/arel/table.rb
+++ b/lib/arel/table.rb
@@ -6,40 +6,24 @@ module Arel
@engine = nil
class << self; attr_accessor :engine; end
- attr_accessor :name, :engine, :aliases, :table_alias
+ attr_accessor :name, :aliases, :table_alias
# TableAlias and Table both have a #table_name which is the name of the underlying table
alias :table_name :name
- def initialize name, engine = Table.engine
+ def initialize(name, as: nil, type_caster: nil)
@name = name.to_s
- @engine = engine
@columns = nil
@aliases = []
- @table_alias = nil
- @primary_key = nil
+ @type_caster = type_caster
- if Hash === engine
- @engine = engine[:engine] || Table.engine
-
- # Sometime AR sends an :as parameter to table, to let the table know
- # that it is an Alias. We may want to override new, and return a
- # TableAlias node?
- @table_alias = engine[:as] unless engine[:as].to_s == @name
- end
- end
-
- def primary_key
- if $VERBOSE
- warn <<-eowarn
-primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0
- eowarn
- end
- @primary_key ||= begin
- primary_key_name = @engine.connection.primary_key(name)
- # some tables might be without primary key
- primary_key_name && self[primary_key_name]
+ # Sometime AR sends an :as parameter to table, to let the table know
+ # that it is an Alias. We may want to override new, and return a
+ # TableAlias node?
+ if as.to_s == @name
+ as = nil
end
+ @table_alias = as
end
def alias name = "#{self.name}_2"
@@ -48,12 +32,12 @@ primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0
end
end
- def from table
- SelectManager.new(@engine, table)
+ def from
+ SelectManager.new(self)
end
def join relation, klass = Nodes::InnerJoin
- return from(self) unless relation
+ return from unless relation
case relation
when String, Nodes::SqlLiteral
@@ -61,7 +45,7 @@ primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0
klass = Nodes::StringJoin
end
- from(self).join(relation, klass)
+ from.join(relation, klass)
end
def outer_join relation
@@ -69,55 +53,39 @@ primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0
end
def group *columns
- from(self).group(*columns)
+ from.group(*columns)
end
def order *expr
- from(self).order(*expr)
+ from.order(*expr)
end
def where condition
- from(self).where condition
+ from.where condition
end
def project *things
- from(self).project(*things)
+ from.project(*things)
end
def take amount
- from(self).take amount
+ from.take amount
end
def skip amount
- from(self).skip amount
+ from.skip amount
end
def having expr
- from(self).having expr
+ from.having expr
end
def [] name
::Arel::Attribute.new self, name
end
- def select_manager
- SelectManager.new(@engine)
- end
-
- def insert_manager
- InsertManager.new(@engine)
- end
-
- def update_manager
- UpdateManager.new(@engine)
- end
-
- def delete_manager
- DeleteManager.new(@engine)
- end
-
def hash
- # Perf note: aliases, table alias and engine is excluded from the hash
+ # Perf note: aliases and table alias is excluded from the hash
# aliases can have a loop back to this table breaking hashes in parent
# relations, for the vast majority of cases @name is unique to a query
@name.hash
@@ -126,12 +94,23 @@ primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0
def eql? other
self.class == other.class &&
self.name == other.name &&
- self.engine == other.engine &&
self.aliases == other.aliases &&
self.table_alias == other.table_alias
end
alias :== :eql?
+ def type_cast_for_database(attribute_name, value)
+ type_caster.type_cast_for_database(attribute_name, value)
+ end
+
+ def able_to_type_cast?
+ !type_caster.nil?
+ end
+
+ protected
+
+ attr_reader :type_caster
+
private
def attributes_for columns
diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb
index 8bff97af78..5278ab06a1 100644
--- a/lib/arel/tree_manager.rb
+++ b/lib/arel/tree_manager.rb
@@ -8,8 +8,7 @@ module Arel
attr_accessor :bind_values
- def initialize engine
- @engine = engine
+ def initialize
@ctx = nil
@bind_values = []
end
@@ -20,13 +19,9 @@ module Arel
collector.value
end
- def visitor
- engine.connection.visitor
- end
-
- def to_sql
+ def to_sql engine = Table.engine
collector = Arel::Collectors::SQLString.new
- collector = visitor.accept @ast, collector
+ collector = engine.connection.visitor.accept @ast, collector
collector.value
end
diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb
index db8cf05f76..36fb74fe7c 100644
--- a/lib/arel/update_manager.rb
+++ b/lib/arel/update_manager.rb
@@ -1,6 +1,6 @@
module Arel
class UpdateManager < Arel::TreeManager
- def initialize engine
+ def initialize
super
@ast = Nodes::UpdateStatement.new
@ctx = @ast
diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb
index 4a8d254ba7..f492ca2d9d 100644
--- a/lib/arel/visitors.rb
+++ b/lib/arel/visitors.rb
@@ -6,6 +6,7 @@ require 'arel/visitors/postgresql'
require 'arel/visitors/mysql'
require 'arel/visitors/mssql'
require 'arel/visitors/oracle'
+require 'arel/visitors/oracle12'
require 'arel/visitors/where_sql'
require 'arel/visitors/dot'
require 'arel/visitors/ibm_db'
diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb
index a434f404c7..22704dd038 100644
--- a/lib/arel/visitors/depth_first.rb
+++ b/lib/arel/visitors/depth_first.rb
@@ -146,7 +146,7 @@ module Arel
visit o.wheres
visit o.groups
visit o.windows
- visit o.having
+ visit o.havings
end
def visit_Arel_Nodes_SelectStatement o
@@ -173,6 +173,12 @@ module Arel
def visit_Hash o
o.each { |k,v| visit(k); visit(v) }
end
+
+ DISPATCH = dispatch_cache
+
+ def get_dispatch_cache
+ DISPATCH
+ end
end
end
end
diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb
index 7e8a3ea458..c33ef50554 100644
--- a/lib/arel/visitors/informix.rb
+++ b/lib/arel/visitors/informix.rb
@@ -34,8 +34,13 @@ module Arel
collector = inject_join o.groups, collector, ", "
end
- maybe_visit o.having, collector
+ if o.havings.any?
+ collector << " HAVING "
+ collector = inject_join o.havings, collector, " AND "
+ end
+ collector
end
+
def visit_Arel_Nodes_Offset o, collector
collector << "SKIP "
visit o.expr, collector
diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb
index 0e5b75ec59..92362a0c5f 100644
--- a/lib/arel/visitors/mssql.rb
+++ b/lib/arel/visitors/mssql.rb
@@ -3,6 +3,11 @@ module Arel
class MSSQL < Arel::Visitors::ToSql
RowNumber = Struct.new :children
+ def initialize(*)
+ @primary_keys = {}
+ super
+ end
+
private
# `top` wouldn't really work here. I.e. User.select("distinct first_name").limit(10) would generate
@@ -61,6 +66,23 @@ module Arel
end
end
+ def visit_Arel_Nodes_DeleteStatement o, collector
+ collector << 'DELETE '
+ if o.limit
+ collector << 'TOP ('
+ visit o.limit.expr, collector
+ collector << ') '
+ end
+ collector << 'FROM '
+ collector = visit o.relation, collector
+ if o.wheres.any?
+ collector << ' WHERE '
+ inject_join o.wheres, collector, AND
+ else
+ collector
+ end
+ end
+
def determine_order_by orders, x
if orders.any?
orders
@@ -81,10 +103,20 @@ module Arel
end
# FIXME raise exception of there is no pk?
- # FIXME!! Table.primary_key will be deprecated. What is the replacement??
def find_left_table_pk o
- return o.primary_key if o.instance_of? Arel::Table
- find_left_table_pk o.left if o.kind_of? Arel::Nodes::Join
+ if o.kind_of?(Arel::Nodes::Join)
+ find_left_table_pk(o.left)
+ elsif o.instance_of?(Arel::Table)
+ find_primary_key(o)
+ end
+ end
+
+ def find_primary_key(o)
+ @primary_keys[o.name] ||= begin
+ primary_key_name = @connection.primary_key(o.name)
+ # some tables might be without primary key
+ primary_key_name && o[primary_key_name]
+ end
end
end
end
diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb
index f989b8ddef..724e0fc43e 100644
--- a/lib/arel/visitors/mysql.rb
+++ b/lib/arel/visitors/mysql.rb
@@ -40,7 +40,7 @@ module Arel
# http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214
def visit_Arel_Nodes_SelectStatement o, collector
if o.offset && !o.limit
- o.limit = Arel::Nodes::Limit.new(Nodes.build_quoted(18446744073709551615))
+ o.limit = Arel::Nodes::Limit.new(18446744073709551615)
end
super
end
diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb
index 91f6e0223e..875b0e5b6a 100644
--- a/lib/arel/visitors/oracle.rb
+++ b/lib/arel/visitors/oracle.rb
@@ -17,7 +17,7 @@ module Arel
if o.limit && o.offset
o = o.dup
- limit = o.limit.expr.expr
+ limit = o.limit.expr
offset = o.offset
o.offset = nil
collector << "
@@ -132,6 +132,10 @@ module Arel
array
end
+ def visit_Arel_Nodes_BindParam o, collector
+ collector.add_bind(o) { |i| ":a#{i}" }
+ end
+
end
end
end
diff --git a/lib/arel/visitors/oracle12.rb b/lib/arel/visitors/oracle12.rb
new file mode 100644
index 0000000000..4a42343c9b
--- /dev/null
+++ b/lib/arel/visitors/oracle12.rb
@@ -0,0 +1,53 @@
+module Arel
+ module Visitors
+ class Oracle12 < Arel::Visitors::ToSql
+ private
+
+ def visit_Arel_Nodes_SelectStatement o, collector
+ # Oracle does not allow LIMIT clause with select for update
+ if o.limit && o.lock
+ o = o.dup
+ o.limit = []
+ end
+
+ super
+ end
+
+ def visit_Arel_Nodes_SelectOptions o, collector
+ collector = maybe_visit o.offset, collector
+ collector = maybe_visit o.limit, collector
+ collector = maybe_visit o.lock, collector
+ end
+
+ def visit_Arel_Nodes_Limit o, collector
+ collector << "FETCH FIRST "
+ collector = visit o.expr, collector
+ collector << " ROWS ONLY"
+ end
+
+ def visit_Arel_Nodes_Offset o, collector
+ collector << "OFFSET "
+ visit o.expr, collector
+ collector << " ROWS"
+ end
+
+ def visit_Arel_Nodes_Except o, collector
+ collector << "( "
+ collector = infix_value o, collector, " MINUS "
+ collector << " )"
+ end
+
+ def visit_Arel_Nodes_UpdateStatement o, collector
+ # Oracle does not allow ORDER BY/LIMIT in UPDATEs.
+ if o.orders.any? && o.limit.nil?
+ # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided,
+ # otherwise let the user deal with the error
+ o = o.dup
+ o.orders = []
+ end
+
+ super
+ end
+ end
+ end
+end
diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb
index 60878ddd20..1ef0261bdd 100644
--- a/lib/arel/visitors/postgresql.rb
+++ b/lib/arel/visitors/postgresql.rb
@@ -4,25 +4,45 @@ module Arel
private
def visit_Arel_Nodes_Matches o, collector
- infix_value o, collector, ' ILIKE '
+ op = o.case_sensitive ? ' LIKE ' : ' ILIKE '
+ collector = infix_value o, collector, op
+ if o.escape
+ collector << ' ESCAPE '
+ visit o.escape, collector
+ else
+ collector
+ end
end
def visit_Arel_Nodes_DoesNotMatch o, collector
- infix_value o, collector, ' NOT ILIKE '
+ op = o.case_sensitive ? ' NOT LIKE ' : ' NOT ILIKE '
+ collector = infix_value o, collector, op
+ if o.escape
+ collector << ' ESCAPE '
+ visit o.escape, collector
+ else
+ collector
+ end
end
def visit_Arel_Nodes_Regexp o, collector
- infix_value o, collector, ' ~ '
+ op = o.case_sensitive ? ' ~ ' : ' ~* '
+ infix_value o, collector, op
end
def visit_Arel_Nodes_NotRegexp o, collector
- infix_value o, collector, ' !~ '
+ op = o.case_sensitive ? ' !~ ' : ' !~* '
+ infix_value o, collector, op
end
def visit_Arel_Nodes_DistinctOn o, collector
collector << "DISTINCT ON ( "
visit(o.expr, collector) << " )"
end
+
+ def visit_Arel_Nodes_BindParam o, collector
+ collector.add_bind(o) { |i| "$#{i}" }
+ end
end
end
end
diff --git a/lib/arel/visitors/reduce.rb b/lib/arel/visitors/reduce.rb
index 1d74934fe5..9670cad27c 100644
--- a/lib/arel/visitors/reduce.rb
+++ b/lib/arel/visitors/reduce.rb
@@ -10,14 +10,14 @@ module Arel
private
def visit object, collector
- send dispatch[object.class.name], object, collector
+ send dispatch[object.class], object, collector
rescue NoMethodError => e
- raise e if respond_to?(dispatch[object.class.name], true)
+ raise e if respond_to?(dispatch[object.class], true)
superklass = object.class.ancestors.find { |klass|
- respond_to?(dispatch[klass.name], true)
+ respond_to?(dispatch[klass], true)
}
raise(TypeError, "Cannot visit #{object.class}") unless superklass
- dispatch[object.class.name] = dispatch[superklass.name]
+ dispatch[object.class] = dispatch[superklass]
retry
end
end
diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb
index a3f8cb565d..ce1fdf80ce 100644
--- a/lib/arel/visitors/to_sql.rb
+++ b/lib/arel/visitors/to_sql.rb
@@ -4,6 +4,12 @@ require 'arel/visitors/reduce'
module Arel
module Visitors
+ class UnsupportedVisitError < StandardError
+ def initialize(object)
+ super "Unsupported argument type: #{object.class.name}. Construct an Arel node instead."
+ end
+ end
+
class ToSql < Arel::Visitors::Reduce
##
# This is some roflscale crazy stuff. I'm roflscaling this because
@@ -74,14 +80,14 @@ module Arel
end
def visit_Arel_Nodes_DeleteStatement o, collector
- collector << "DELETE FROM "
+ collector << 'DELETE FROM '
collector = visit o.relation, collector
if o.wheres.any?
- collector << " WHERE "
- inject_join o.wheres, collector, AND
- else
- collector
+ collector << ' WHERE '
+ collector = inject_join o.wheres, collector, AND
end
+
+ maybe_visit o.limit, collector
end
# FIXME: we should probably have a 2-pass visitor for this
@@ -186,7 +192,8 @@ module Arel
len = o.expressions.length - 1
o.expressions.zip(o.columns).each_with_index { |(value, attr), i|
- if Nodes::SqlLiteral === value
+ case value
+ when Nodes::SqlLiteral, Nodes::BindParam
collector = visit value, collector
else
collector << quote(value, attr && column_for(attr)).to_s
@@ -210,7 +217,6 @@ module Arel
}
unless o.orders.empty?
- collector << SPACE
collector << ORDER_BY
len = o.orders.length - 1
o.orders.each_with_index { |x, i|
@@ -219,11 +225,15 @@ module Arel
}
end
+ visit_Arel_Nodes_SelectOptions(o, collector)
+
+ collector
+ end
+
+ def visit_Arel_Nodes_SelectOptions o, collector
collector = maybe_visit o.limit, collector
collector = maybe_visit o.offset, collector
collector = maybe_visit o.lock, collector
-
- collector
end
def visit_Arel_Nodes_SelectCore o, collector
@@ -265,7 +275,10 @@ module Arel
end
end
- collector = maybe_visit o.having, collector
+ unless o.havings.empty?
+ collector << " HAVING "
+ inject_join o.havings, collector, AND
+ end
unless o.windows.empty?
collector << WINDOW
@@ -404,11 +417,6 @@ module Arel
end
end
- def visit_Arel_Nodes_Having o, collector
- collector << "HAVING "
- visit o.expr, collector
- end
-
def visit_Arel_Nodes_Offset o, collector
collector << "OFFSET "
visit o.expr, collector
@@ -574,8 +582,11 @@ module Arel
visit o.left, collector
end
- def visit_Arel_Nodes_FullOuterJoin o
- "FULL OUTER JOIN #{visit o.left} #{visit o.right}"
+ def visit_Arel_Nodes_FullOuterJoin o, collector
+ collector << "FULL OUTER JOIN "
+ collector = visit o.left, collector
+ collector << SPACE
+ visit o.right, collector
end
def visit_Arel_Nodes_OuterJoin o, collector
@@ -585,8 +596,11 @@ module Arel
visit o.right, collector
end
- def visit_Arel_Nodes_RightOuterJoin o
- "RIGHT OUTER JOIN #{visit o.left} #{visit o.right}"
+ def visit_Arel_Nodes_RightOuterJoin o, collector
+ collector << "RIGHT OUTER JOIN "
+ collector = visit o.left, collector
+ collector << SPACE
+ visit o.right, collector
end
def visit_Arel_Nodes_InnerJoin o, collector
@@ -713,7 +727,7 @@ module Arel
def literal o, collector; collector << o.to_s; end
def visit_Arel_Nodes_BindParam o, collector
- collector.add_bind o
+ collector.add_bind(o) { "?" }
end
alias :visit_Arel_Nodes_SqlLiteral :literal
@@ -721,11 +735,15 @@ module Arel
alias :visit_Fixnum :literal
def quoted o, a
- quote(o, column_for(a))
+ if a && a.able_to_type_cast?
+ quote(a.type_cast_for_database(o))
+ else
+ quote(o, column_for(a))
+ end
end
def unsupported o, collector
- raise "unsupported: #{o.class.name}"
+ raise UnsupportedVisitError.new(o)
end
alias :visit_ActiveSupport_Multibyte_Chars :unsupported
@@ -761,6 +779,9 @@ module Arel
def quote value, column = nil
return value if Arel::Nodes::SqlLiteral === value
+ if column
+ print_type_cast_deprecation
+ end
@connection.quote value, column
end
@@ -810,6 +831,20 @@ module Arel
collector
end
end
+
+ def print_type_cast_deprecation
+ unless defined?($arel_silence_type_casting_deprecation) && $arel_silence_type_casting_deprecation
+ warn <<-eowarn
+Arel performing automatic type casting is deprecated, and will be removed in Arel 8.0. If you are seeing this, it is because you are manually passing a value to an Arel predicate, and the `Arel::Table` object was constructed manually. The easiest way to remove this warning is to use an `Arel::Table` object returned from calling `arel_table` on an ActiveRecord::Base subclass.
+
+If you're certain the value is already of the right type, change `attribute.eq(value)` to `attribute.eq(Arel::Nodes::Quoted.new(value))` (you will be able to remove that in Arel 8.0, it is only required to silence this deprecation warning).
+
+You can also silence this warning globally by setting `$arel_silence_type_casting_deprecation` to `true`. (Do NOT do this if you are a library author)
+
+If you are passing user input to a predicate, you must either give an appropriate type caster object to the `Arel::Table`, or manually cast the value before passing it to Arel.
+ eowarn
+ end
+ end
end
end
end
diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb
index 2317d0c95f..bfe7342f04 100644
--- a/lib/arel/visitors/visitor.rb
+++ b/lib/arel/visitors/visitor.rb
@@ -2,17 +2,7 @@ module Arel
module Visitors
class Visitor
def initialize
- @dispatch = Hash.new do |hash, class_name|
- raise if class_name == 'Arel::Nodes::Union'
- hash[class_name] = "visit_#{(class_name || '').gsub('::', '_')}"
- end
-
- # pre-populate cache. FIXME: this should be passed in to each
- # instance, but we can do that later.
- self.class.private_instance_methods.sort.each do |name|
- next unless name =~ /^visit_(.*)$/
- @dispatch[$1.gsub('_', '::')] = name
- end
+ @dispatch = get_dispatch_cache
end
def accept object
@@ -21,19 +11,29 @@ module Arel
private
+ def self.dispatch_cache
+ Hash.new do |hash, klass|
+ hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}"
+ end
+ end
+
+ def get_dispatch_cache
+ self.class.dispatch_cache
+ end
+
def dispatch
@dispatch
end
def visit object
- send dispatch[object.class.name], object
+ send dispatch[object.class], object
rescue NoMethodError => e
- raise e if respond_to?(dispatch[object.class.name], true)
+ raise e if respond_to?(dispatch[object.class], true)
superklass = object.class.ancestors.find { |klass|
- respond_to?(dispatch[klass.name], true)
+ respond_to?(dispatch[klass], true)
}
raise(TypeError, "Cannot visit #{object.class}") unless superklass
- dispatch[object.class.name] = dispatch[superklass.name]
+ dispatch[object.class] = dispatch[superklass]
retry
end
end
diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb
index 768df23d4d..4e55069df4 100644
--- a/test/attributes/test_attribute.rb
+++ b/test/attributes/test_attribute.rb
@@ -1,4 +1,5 @@
require 'helper'
+require 'ostruct'
module Arel
module Attributes
@@ -557,15 +558,155 @@ module Arel
end
end
+ describe 'with a range' do
+ it 'can be constructed with a standard range' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(1..3)
+
+ node.must_equal Nodes::Between.new(
+ attribute,
+ Nodes::And.new([
+ Nodes::Casted.new(1, attribute),
+ Nodes::Casted.new(3, attribute)
+ ])
+ )
+ end
+
+ it 'can be constructed with a range starting from -Infinity' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(-::Float::INFINITY..3)
+
+ node.must_equal Nodes::LessThanOrEqual.new(
+ attribute,
+ Nodes::Casted.new(3, attribute)
+ )
+ end
+
+ it 'can be constructed with a quoted range starting from -Infinity' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(quoted_range(-::Float::INFINITY, 3, false))
+
+ node.must_equal Nodes::LessThanOrEqual.new(
+ attribute,
+ Nodes::Quoted.new(3)
+ )
+ end
+
+ it 'can be constructed with an exclusive range starting from -Infinity' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(-::Float::INFINITY...3)
+
+ node.must_equal Nodes::LessThan.new(
+ attribute,
+ Nodes::Casted.new(3, attribute)
+ )
+ end
+
+ it 'can be constructed with a quoted exclusive range starting from -Infinity' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(quoted_range(-::Float::INFINITY, 3, true))
+
+ node.must_equal Nodes::LessThan.new(
+ attribute,
+ Nodes::Quoted.new(3)
+ )
+ end
+
+ it 'can be constructed with an infinite range' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(-::Float::INFINITY..::Float::INFINITY)
+
+ node.must_equal Nodes::NotIn.new(attribute, [])
+ end
+
+ it 'can be constructed with a quoted infinite range' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(quoted_range(-::Float::INFINITY, ::Float::INFINITY, false))
+
+ node.must_equal Nodes::NotIn.new(attribute, [])
+ end
+
+
+ it 'can be constructed with a range ending at Infinity' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(0..::Float::INFINITY)
+
+ node.must_equal Nodes::GreaterThanOrEqual.new(
+ attribute,
+ Nodes::Casted.new(0, attribute)
+ )
+ end
+
+ it 'can be constructed with a quoted range ending at Infinity' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(quoted_range(0, ::Float::INFINITY, false))
+
+ node.must_equal Nodes::GreaterThanOrEqual.new(
+ attribute,
+ Nodes::Quoted.new(0)
+ )
+ end
+
+ it 'can be constructed with an exclusive range' do
+ attribute = Attribute.new nil, nil
+ node = attribute.between(0...3)
+
+ node.must_equal Nodes::And.new([
+ Nodes::GreaterThanOrEqual.new(
+ attribute,
+ Nodes::Casted.new(0, attribute)
+ ),
+ Nodes::LessThan.new(
+ attribute,
+ Nodes::Casted.new(3, attribute)
+ )
+ ])
+ end
+
+ def quoted_range(begin_val, end_val, exclude)
+ OpenStruct.new(
+ begin: Nodes::Quoted.new(begin_val),
+ end: Nodes::Quoted.new(end_val),
+ exclude_end?: exclude,
+ )
+ end
+ end
+
describe '#in' do
+ it 'can be constructed with a subquery' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%'])
+ attribute = Attribute.new nil, nil
+
+ node = attribute.in(mgr)
+
+ node.must_equal Nodes::In.new(attribute, mgr.ast)
+ end
+
it 'can be constructed with a list' do
+ attribute = Attribute.new nil, nil
+ node = attribute.in([1, 2, 3])
+
+ node.must_equal Nodes::In.new(
+ attribute,
+ [
+ Nodes::Casted.new(1, attribute),
+ Nodes::Casted.new(2, attribute),
+ Nodes::Casted.new(3, attribute),
+ ]
+ )
end
- it 'should return an in node' do
+ it 'can be constructed with a random object' do
attribute = Attribute.new nil, nil
- node = Nodes::In.new attribute, [1,2,3]
- node.left.must_equal attribute
- node.right.must_equal [1, 2, 3]
+ random_object = Object.new
+ node = attribute.in(random_object)
+
+ node.must_equal Nodes::In.new(
+ attribute,
+ Nodes::Casted.new(random_object, attribute)
+ )
end
it 'should generate IN in sql' do
@@ -610,13 +751,112 @@ module Arel
end
end
+ describe 'with a range' do
+ it 'can be constructed with a standard range' do
+ attribute = Attribute.new nil, nil
+ node = attribute.not_between(1..3)
+
+ node.must_equal Nodes::Grouping.new(Nodes::Or.new(
+ Nodes::LessThan.new(
+ attribute,
+ Nodes::Casted.new(1, attribute)
+ ),
+ Nodes::GreaterThan.new(
+ attribute,
+ Nodes::Casted.new(3, attribute)
+ )
+ ))
+ end
+
+ it 'can be constructed with a range starting from -Infinity' do
+ attribute = Attribute.new nil, nil
+ node = attribute.not_between(-::Float::INFINITY..3)
+
+ node.must_equal Nodes::GreaterThan.new(
+ attribute,
+ Nodes::Casted.new(3, attribute)
+ )
+ end
+
+ it 'can be constructed with an exclusive range starting from -Infinity' do
+ attribute = Attribute.new nil, nil
+ node = attribute.not_between(-::Float::INFINITY...3)
+
+ node.must_equal Nodes::GreaterThanOrEqual.new(
+ attribute,
+ Nodes::Casted.new(3, attribute)
+ )
+ end
+
+ it 'can be constructed with an infinite range' do
+ attribute = Attribute.new nil, nil
+ node = attribute.not_between(-::Float::INFINITY..::Float::INFINITY)
+
+ node.must_equal Nodes::In.new(attribute, [])
+ end
+
+ it 'can be constructed with a range ending at Infinity' do
+ attribute = Attribute.new nil, nil
+ node = attribute.not_between(0..::Float::INFINITY)
+
+ node.must_equal Nodes::LessThan.new(
+ attribute,
+ Nodes::Casted.new(0, attribute)
+ )
+ end
+
+ it 'can be constructed with an exclusive range' do
+ attribute = Attribute.new nil, nil
+ node = attribute.not_between(0...3)
+
+ node.must_equal Nodes::Grouping.new(Nodes::Or.new(
+ Nodes::LessThan.new(
+ attribute,
+ Nodes::Casted.new(0, attribute)
+ ),
+ Nodes::GreaterThanOrEqual.new(
+ attribute,
+ Nodes::Casted.new(3, attribute)
+ )
+ ))
+ end
+ end
+
describe '#not_in' do
+ it 'can be constructed with a subquery' do
+ relation = Table.new(:users)
+ mgr = relation.project relation[:id]
+ mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%'])
+ attribute = Attribute.new nil, nil
+
+ node = attribute.not_in(mgr)
+
+ node.must_equal Nodes::NotIn.new(attribute, mgr.ast)
+ end
+
+ it 'can be constructed with a list' do
+ attribute = Attribute.new nil, nil
+ node = attribute.not_in([1, 2, 3])
+
+ node.must_equal Nodes::NotIn.new(
+ attribute,
+ [
+ Nodes::Casted.new(1, attribute),
+ Nodes::Casted.new(2, attribute),
+ Nodes::Casted.new(3, attribute),
+ ]
+ )
+ end
- it 'should return a NotIn node' do
+ it 'can be constructed with a random object' do
attribute = Attribute.new nil, nil
- node = Nodes::NotIn.new attribute, [1,2,3]
- node.left.must_equal attribute
- node.right.must_equal [1, 2, 3]
+ random_object = Object.new
+ node = attribute.not_in(random_object)
+
+ node.must_equal Nodes::NotIn.new(
+ attribute,
+ Nodes::Casted.new(random_object, attribute)
+ )
end
it 'should generate NOT IN in sql' do
@@ -719,5 +959,39 @@ module Arel
end
end
end
+
+ describe 'type casting' do
+ it 'does not type cast by default' do
+ table = Table.new(:foo)
+ condition = table["id"].eq("1")
+
+ refute table.able_to_type_cast?
+ condition.to_sql.must_equal %("foo"."id" = '1')
+ end
+
+ it 'type casts when given an explicit caster' do
+ fake_caster = Object.new
+ def fake_caster.type_cast_for_database(attr_name, value)
+ if attr_name == "id"
+ value.to_i
+ else
+ value
+ end
+ end
+ table = Table.new(:foo, type_caster: fake_caster)
+ condition = table["id"].eq("1").and(table["other_id"].eq("2"))
+
+ assert table.able_to_type_cast?
+ condition.to_sql.must_equal %("foo"."id" = 1 AND "foo"."other_id" = '2')
+ end
+
+ it 'falls back to using the connection adapter for type casting' do
+ table = Table.new(:users)
+ condition = table["id"].eq("1")
+
+ refute table.able_to_type_cast?
+ condition.to_sql.must_equal %("users"."id" = 1)
+ end
+ end
end
end
diff --git a/test/collectors/test_bind_collector.rb b/test/collectors/test_bind_collector.rb
index 60532f061c..fc7df2fc45 100644
--- a/test/collectors/test_bind_collector.rb
+++ b/test/collectors/test_bind_collector.rb
@@ -20,21 +20,21 @@ module Arel
def ast_with_binds bv
table = Table.new(:users)
- manager = Arel::SelectManager.new Table.engine, table
+ manager = Arel::SelectManager.new table
manager.where(table[:age].eq(bv))
manager.where(table[:name].eq(bv))
manager.ast
end
def test_leaves_binds
- node = Nodes::BindParam.new 'omg'
+ node = Nodes::BindParam.new
list = compile node
assert_equal node, list.first
assert_equal node.class, list.first.class
end
def test_adds_strings
- bv = Nodes::BindParam.new('?')
+ bv = Nodes::BindParam.new
list = compile ast_with_binds bv
assert_operator list.length, :>, 0
assert_equal bv, list.grep(Nodes::BindParam).first
@@ -42,7 +42,7 @@ module Arel
end
def test_substitute_binds
- bv = Nodes::BindParam.new('?')
+ bv = Nodes::BindParam.new
collector = collect ast_with_binds bv
values = collector.value
@@ -59,7 +59,7 @@ module Arel
end
def test_compile
- bv = Nodes::BindParam.new('?')
+ bv = Nodes::BindParam.new
collector = collect ast_with_binds bv
sql = collector.compile ["hello", "world"]
diff --git a/test/collectors/test_sql_string.rb b/test/collectors/test_sql_string.rb
index 6d2e23151b..37a9e41f71 100644
--- a/test/collectors/test_sql_string.rb
+++ b/test/collectors/test_sql_string.rb
@@ -20,14 +20,14 @@ module Arel
def ast_with_binds bv
table = Table.new(:users)
- manager = Arel::SelectManager.new Table.engine, table
+ manager = Arel::SelectManager.new table
manager.where(table[:age].eq(bv))
manager.where(table[:name].eq(bv))
manager.ast
end
def test_compile
- bv = Nodes::BindParam.new('?')
+ bv = Nodes::BindParam.new
collector = collect ast_with_binds bv
sql = collector.compile ["hello", "world"]
diff --git a/test/helper.rb b/test/helper.rb
index 6e8ac836fc..87f5756d24 100644
--- a/test/helper.rb
+++ b/test/helper.rb
@@ -6,6 +6,8 @@ require 'arel'
require 'support/fake_record'
Arel::Table.engine = FakeRecord::Base.new
+$arel_silence_type_casting_deprecation = true
+
class Object
def must_be_like other
gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip
diff --git a/test/nodes/test_binary.rb b/test/nodes/test_binary.rb
new file mode 100644
index 0000000000..7e25a21151
--- /dev/null
+++ b/test/nodes/test_binary.rb
@@ -0,0 +1,26 @@
+require 'helper'
+require 'set'
+
+module Arel
+ module Nodes
+ describe 'Binary' do
+ describe '#hash' do
+ it 'generates a hash based on its value' do
+ eq = Equality.new('foo', 'bar')
+ eq2 = Equality.new('foo', 'bar')
+ eq3 = Equality.new('bar', 'baz')
+
+ assert_equal eq.hash, eq2.hash
+ refute_equal eq.hash, eq3.hash
+ end
+
+ it 'generates a hash specific to its class' do
+ eq = Equality.new('foo', 'bar')
+ neq = NotEqual.new('foo', 'bar')
+
+ refute_equal eq.hash, neq.hash
+ end
+ end
+ end
+ end
+end
diff --git a/test/nodes/test_bind_param.rb b/test/nodes/test_bind_param.rb
new file mode 100644
index 0000000000..ea008f4c99
--- /dev/null
+++ b/test/nodes/test_bind_param.rb
@@ -0,0 +1,15 @@
+require 'helper'
+
+module Arel
+ module Nodes
+ describe 'BindParam' do
+ it 'is equal to other bind params' do
+ BindParam.new.must_equal(BindParam.new)
+ end
+
+ it 'is not equal to other nodes' do
+ BindParam.new.wont_equal(Node.new)
+ end
+ end
+ end
+end
diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb
index ca4f070444..4114bcf4ff 100644
--- a/test/nodes/test_select_core.rb
+++ b/test/nodes/test_select_core.rb
@@ -34,14 +34,14 @@ module Arel
core1.wheres = %w[g h i]
core1.groups = %w[j k l]
core1.windows = %w[m n o]
- core1.having = %w[p q r]
+ core1.havings = %w[p q r]
core2 = SelectCore.new
core2.froms = %w[a b c]
core2.projections = %w[d e f]
core2.wheres = %w[g h i]
core2.groups = %w[j k l]
core2.windows = %w[m n o]
- core2.having = %w[p q r]
+ core2.havings = %w[p q r]
array = [core1, core2]
assert_equal 1, array.uniq.size
end
@@ -53,14 +53,14 @@ module Arel
core1.wheres = %w[g h i]
core1.groups = %w[j k l]
core1.windows = %w[m n o]
- core1.having = %w[p q r]
+ core1.havings = %w[p q r]
core2 = SelectCore.new
core2.froms = %w[a b c]
core2.projections = %w[d e f]
core2.wheres = %w[g h i]
core2.groups = %w[j k l]
core2.windows = %w[m n o]
- core2.having = %w[l o l]
+ core2.havings = %w[l o l]
array = [core1, core2]
assert_equal 2, array.uniq.size
end
diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb
index ed602cc47d..c09e5882d5 100644
--- a/test/nodes/test_sql_literal.rb
+++ b/test/nodes/test_sql_literal.rb
@@ -56,7 +56,7 @@ module Arel
end
describe 'grouped "and" equality' do
- it 'makes a grouping node with an or node' do
+ it 'makes a grouping node with an and node' do
node = SqlLiteral.new('foo').eq_all([1,2])
compile(node).must_be_like %{ (foo = 1 AND foo = 2) }
end
diff --git a/test/nodes/test_sum.rb b/test/nodes/test_sum.rb
index d65cd31d4b..d387e7f9ef 100644
--- a/test/nodes/test_sum.rb
+++ b/test/nodes/test_sum.rb
@@ -21,4 +21,13 @@ describe Arel::Nodes::Sum do
assert_equal 2, array.uniq.size
end
end
+
+ describe 'order' do
+ it 'should order the sum' do
+ table = Arel::Table.new :users
+ table[:id].sum.desc.to_sql.must_be_like %{
+ SUM("users"."id") DESC
+ }
+ end
+ end
end
diff --git a/test/nodes/test_table_alias.rb b/test/nodes/test_table_alias.rb
index 4aafd12b79..57c9a42fc6 100644
--- a/test/nodes/test_table_alias.rb
+++ b/test/nodes/test_table_alias.rb
@@ -4,28 +4,20 @@ require 'ostruct'
module Arel
module Nodes
describe 'table alias' do
- it 'has an #engine which delegates to the relation' do
- engine = 'vroom'
- relation = Table.new(:users, engine)
-
- node = TableAlias.new relation, :foo
- node.engine.must_equal engine
- end
-
describe 'equality' do
it 'is equal with equal ivars' do
- relation1 = Table.new(:users, 'vroom')
+ relation1 = Table.new(:users)
node1 = TableAlias.new relation1, :foo
- relation2 = Table.new(:users, 'vroom')
+ relation2 = Table.new(:users)
node2 = TableAlias.new relation2, :foo
array = [node1, node2]
assert_equal 1, array.uniq.size
end
it 'is not equal with different ivars' do
- relation1 = Table.new(:users, 'vroom')
+ relation1 = Table.new(:users)
node1 = TableAlias.new relation1, :foo
- relation2 = Table.new(:users, 'vroom')
+ relation2 = Table.new(:users)
node2 = TableAlias.new relation2, :bar
array = [node1, node2]
assert_equal 2, array.uniq.size
diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb
index fd12c5acd2..ece2389d88 100644
--- a/test/test_delete_manager.rb
+++ b/test/test_delete_manager.rb
@@ -4,21 +4,29 @@ module Arel
describe 'delete manager' do
describe 'new' do
it 'takes an engine' do
- Arel::DeleteManager.new Table.engine
+ Arel::DeleteManager.new
end
end
+ it 'handles limit properly' do
+ table = Table.new(:users)
+ dm = Arel::DeleteManager.new
+ dm.take 10
+ dm.from table
+ assert_match(/LIMIT 10/, dm.to_sql)
+ end
+
describe 'from' do
it 'uses from' do
table = Table.new(:users)
- dm = Arel::DeleteManager.new Table.engine
+ dm = Arel::DeleteManager.new
dm.from table
dm.to_sql.must_be_like %{ DELETE FROM "users" }
end
it 'chains' do
table = Table.new(:users)
- dm = Arel::DeleteManager.new Table.engine
+ dm = Arel::DeleteManager.new
dm.from(table).must_equal dm
end
end
@@ -26,7 +34,7 @@ module Arel
describe 'where' do
it 'uses where values' do
table = Table.new(:users)
- dm = Arel::DeleteManager.new Table.engine
+ dm = Arel::DeleteManager.new
dm.from table
dm.where table[:id].eq(10)
dm.to_sql.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10}
@@ -34,7 +42,7 @@ module Arel
it 'chains' do
table = Table.new(:users)
- dm = Arel::DeleteManager.new Table.engine
+ dm = Arel::DeleteManager.new
dm.where(table[:id].eq(10)).must_equal dm
end
end
diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb
index 9cfd01262b..4289b0fa8c 100644
--- a/test/test_insert_manager.rb
+++ b/test/test_insert_manager.rb
@@ -4,13 +4,13 @@ module Arel
describe 'insert manager' do
describe 'new' do
it 'takes an engine' do
- Arel::InsertManager.new Table.engine
+ Arel::InsertManager.new
end
end
describe 'insert' do
it 'can create a Values node' do
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
values = manager.create_values %w{ a b }, %w{ c d }
assert_kind_of Arel::Nodes::Values, values
@@ -19,7 +19,7 @@ module Arel
end
it 'allows sql literals' do
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.into Table.new(:users)
manager.values = manager.create_values [Arel.sql('*')], %w{ a }
manager.to_sql.must_be_like %{
@@ -29,7 +29,7 @@ module Arel
it "inserts false" do
table = Table.new(:users)
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.insert [[table[:bool], false]]
manager.to_sql.must_be_like %{
@@ -39,7 +39,7 @@ module Arel
it "inserts null" do
table = Table.new(:users)
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.insert [[table[:id], nil]]
manager.to_sql.must_be_like %{
INSERT INTO "users" ("id") VALUES (NULL)
@@ -48,7 +48,7 @@ module Arel
it "inserts time" do
table = Table.new(:users)
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
time = Time.now
attribute = table[:created_at]
@@ -61,7 +61,7 @@ module Arel
it 'takes a list of lists' do
table = Table.new(:users)
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.into table
manager.insert [[table[:id], 1], [table[:name], 'aaron']]
manager.to_sql.must_be_like %{
@@ -71,7 +71,7 @@ module Arel
it 'defaults the table' do
table = Table.new(:users)
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.insert [[table[:id], 1], [table[:name], 'aaron']]
manager.to_sql.must_be_like %{
INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
@@ -80,7 +80,7 @@ module Arel
it 'noop for empty list' do
table = Table.new(:users)
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.insert [[table[:id], 1]]
manager.insert []
manager.to_sql.must_be_like %{
@@ -91,13 +91,13 @@ module Arel
describe 'into' do
it 'takes a Table and chains' do
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.into(Table.new(:users)).must_equal manager
end
it 'converts to sql' do
table = Table.new :users
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.into table
manager.to_sql.must_be_like %{
INSERT INTO "users"
@@ -108,7 +108,7 @@ module Arel
describe 'columns' do
it "converts to sql" do
table = Table.new :users
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.into table
manager.columns << table[:id]
manager.to_sql.must_be_like %{
@@ -120,7 +120,7 @@ module Arel
describe "values" do
it "converts to sql" do
table = Table.new :users
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.into table
manager.values = Nodes::Values.new [1]
@@ -133,7 +133,7 @@ module Arel
describe "combo" do
it "combines columns and values list in order" do
table = Table.new :users
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.into table
manager.values = Nodes::Values.new [1, 'aaron']
@@ -150,10 +150,10 @@ module Arel
it "accepts a select query in place of a VALUES clause" do
table = Table.new :users
- manager = Arel::InsertManager.new Table.engine
+ manager = Arel::InsertManager.new
manager.into table
- select = Arel::SelectManager.new Table.engine
+ select = Arel::SelectManager.new
select.project Arel.sql('1')
select.project Arel.sql('"aaron"')
diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb
index 1ffb56fd9f..8425cee031 100644
--- a/test/test_select_manager.rb
+++ b/test/test_select_manager.rb
@@ -4,13 +4,13 @@ module Arel
describe 'select manager' do
def test_join_sources
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.join_sources << Arel::Nodes::StringJoin.new(Nodes.build_quoted('foo'))
assert_equal "SELECT FROM 'foo'", manager.to_sql
end
def test_manager_stores_bind_values
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
assert_equal [], manager.bind_values
manager.bind_values = [1]
assert_equal [1], manager.bind_values
@@ -20,7 +20,7 @@ module Arel
describe 'project' do
it 'accepts symbols as sql literals' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project :id
manager.from table
manager.to_sql.must_be_like %{
@@ -32,7 +32,7 @@ module Arel
describe 'order' do
it 'accepts symbols' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Nodes::SqlLiteral.new '*'
manager.from table
manager.order :foo
@@ -43,7 +43,7 @@ module Arel
describe 'group' do
it 'takes a symbol' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.group :foo
manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo }
@@ -52,7 +52,7 @@ module Arel
describe 'as' do
it 'makes an AS node by grouping the AST' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
as = manager.as(Arel.sql('foo'))
assert_kind_of Arel::Nodes::Grouping, as.left
assert_equal manager.ast, as.left.expr
@@ -60,18 +60,18 @@ module Arel
end
it 'converts right to SqlLiteral if a string' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
as = manager.as('foo')
assert_kind_of Arel::Nodes::SqlLiteral, as.right
end
it 'can make a subselect' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Arel.star
manager.from Arel.sql('zomg')
as = manager.as(Arel.sql('foo'))
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Arel.sql('name')
manager.from as
manager.to_sql.must_be_like "SELECT name FROM (SELECT * FROM zomg) foo"
@@ -81,7 +81,7 @@ module Arel
describe 'from' do
it 'ignores strings when table of same name exists' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.from 'users'
@@ -91,9 +91,9 @@ module Arel
it 'should support any ast' do
table = Table.new :users
- manager1 = Arel::SelectManager.new Table.engine
+ manager1 = Arel::SelectManager.new
- manager2 = Arel::SelectManager.new Table.engine
+ manager2 = Arel::SelectManager.new
manager2.project(Arel.sql('*'))
manager2.from table
@@ -110,23 +110,23 @@ module Arel
describe 'having' do
it 'converts strings to SQLLiterals' do
table = Table.new :users
- mgr = table.from table
- mgr.having 'foo'
+ mgr = table.from
+ mgr.having Arel.sql('foo')
mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo }
end
it 'can have multiple items specified separately' do
table = Table.new :users
- mgr = table.from table
- mgr.having 'foo'
- mgr.having 'bar'
+ mgr = table.from
+ mgr.having Arel.sql('foo')
+ mgr.having Arel.sql('bar')
mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar }
end
- it 'can have multiple items specified together' do
+ it 'can receive any node' do
table = Table.new :users
- mgr = table.from table
- mgr.having 'foo', 'bar'
+ mgr = table.from
+ mgr.having Arel::Nodes::And.new([Arel.sql('foo'), Arel.sql('bar')])
mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar }
end
end
@@ -135,7 +135,7 @@ module Arel
it 'converts to sqlliterals' do
table = Table.new :users
right = table.alias
- mgr = table.from table
+ mgr = table.from
mgr.join(right).on("omg")
mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg }
end
@@ -143,7 +143,7 @@ module Arel
it 'converts to sqlliterals with multiple items' do
table = Table.new :users
right = table.alias
- mgr = table.from table
+ mgr = table.from
mgr.join(right).on("omg", "123")
mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg AND 123 }
end
@@ -153,7 +153,7 @@ module Arel
describe 'clone' do
it 'creates new cores' do
table = Table.new :users, :as => 'foo'
- mgr = table.from table
+ mgr = table.from
m2 = mgr.clone
m2.project "foo"
mgr.to_sql.wont_equal m2.to_sql
@@ -161,7 +161,7 @@ module Arel
it 'makes updates to the correct copy' do
table = Table.new :users, :as => 'foo'
- mgr = table.from table
+ mgr = table.from
m2 = mgr.clone
m3 = m2.clone
m2.project "foo"
@@ -173,7 +173,7 @@ module Arel
describe 'initialize' do
it 'uses alias in sql' do
table = Table.new :users, :as => 'foo'
- mgr = table.from table
+ mgr = table.from
mgr.skip 10
mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 }
end
@@ -182,14 +182,14 @@ module Arel
describe 'skip' do
it 'should add an offset' do
table = Table.new :users
- mgr = table.from table
+ mgr = table.from
mgr.skip 10
mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
end
it 'should chain' do
table = Table.new :users
- mgr = table.from table
+ mgr = table.from
mgr.skip(10).to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
end
end
@@ -197,14 +197,14 @@ module Arel
describe 'offset' do
it 'should add an offset' do
table = Table.new :users
- mgr = table.from table
+ mgr = table.from
mgr.offset = 10
mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
end
it 'should remove an offset' do
table = Table.new :users
- mgr = table.from table
+ mgr = table.from
mgr.offset = 10
mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
@@ -214,7 +214,7 @@ module Arel
it 'should return the offset' do
table = Table.new :users
- mgr = table.from table
+ mgr = table.from
mgr.offset = 10
assert_equal 10, mgr.offset
end
@@ -223,7 +223,7 @@ module Arel
describe 'exists' do
it 'should create an exists clause' do
table = Table.new(:users)
- manager = Arel::SelectManager.new Table.engine, table
+ manager = Arel::SelectManager.new table
manager.project Nodes::SqlLiteral.new '*'
m2 = Arel::SelectManager.new(manager.engine)
m2.project manager.exists
@@ -232,7 +232,7 @@ module Arel
it 'can be aliased' do
table = Table.new(:users)
- manager = Arel::SelectManager.new Table.engine, table
+ manager = Arel::SelectManager.new table
manager.project Nodes::SqlLiteral.new '*'
m2 = Arel::SelectManager.new(manager.engine)
m2.project manager.exists.as('foo')
@@ -243,11 +243,11 @@ module Arel
describe 'union' do
before do
table = Table.new :users
- @m1 = Arel::SelectManager.new Table.engine, table
+ @m1 = Arel::SelectManager.new table
@m1.project Arel.star
@m1.where(table[:age].lt(18))
- @m2 = Arel::SelectManager.new Table.engine, table
+ @m2 = Arel::SelectManager.new table
@m2.project Arel.star
@m2.where(table[:age].gt(99))
@@ -278,11 +278,11 @@ module Arel
describe 'intersect' do
before do
table = Table.new :users
- @m1 = Arel::SelectManager.new Table.engine, table
+ @m1 = Arel::SelectManager.new table
@m1.project Arel.star
@m1.where(table[:age].gt(18))
- @m2 = Arel::SelectManager.new Table.engine, table
+ @m2 = Arel::SelectManager.new table
@m2.project Arel.star
@m2.where(table[:age].lt(99))
@@ -305,15 +305,13 @@ module Arel
describe 'except' do
before do
table = Table.new :users
- @m1 = Arel::SelectManager.new Table.engine, table
+ @m1 = Arel::SelectManager.new table
@m1.project Arel.star
- @m1.where(table[:age].in(18..60))
+ @m1.where(table[:age].between(18..60))
- @m2 = Arel::SelectManager.new Table.engine, table
+ @m2 = Arel::SelectManager.new table
@m2.project Arel.star
- @m2.where(table[:age].in(40..99))
-
-
+ @m2.where(table[:age].between(40..99))
end
it 'should except two managers' do
@@ -353,17 +351,17 @@ module Arel
replies = Table.new(:replies)
replies_id = replies[:id]
- recursive_term = Arel::SelectManager.new Table.engine
+ recursive_term = Arel::SelectManager.new
recursive_term.from(comments).project(comments_id, comments_parent_id).where(comments_id.eq 42)
- non_recursive_term = Arel::SelectManager.new Table.engine
+ non_recursive_term = Arel::SelectManager.new
non_recursive_term.from(comments).project(comments_id, comments_parent_id).join(replies).on(comments_parent_id.eq replies_id)
union = recursive_term.union(non_recursive_term)
as_statement = Arel::Nodes::As.new replies, union
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.with(:recursive, as_statement).from(replies).project(Arel.star)
sql = manager.to_sql
@@ -381,13 +379,13 @@ module Arel
describe 'ast' do
it 'should return the ast' do
table = Table.new :users
- mgr = table.from table
+ mgr = table.from
assert mgr.ast
end
it 'should allow orders to work when the ast is grepped' do
table = Table.new :users
- mgr = table.from table
+ mgr = table.from
mgr.project Arel.sql '*'
mgr.from table
mgr.orders << Arel::Nodes::Ascending.new(Arel.sql('foo'))
@@ -398,7 +396,7 @@ module Arel
describe 'taken' do
it 'should return limit' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.take 10
manager.taken.must_equal 10
end
@@ -408,7 +406,7 @@ module Arel
# This should fail on other databases
it 'adds a lock node' do
table = Table.new :users
- mgr = table.from table
+ mgr = table.from
mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" FOR UPDATE }
end
end
@@ -416,7 +414,7 @@ module Arel
describe 'orders' do
it 'returns order clauses' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
order = table[:id]
manager.order table[:id]
manager.orders.must_equal [order]
@@ -426,7 +424,7 @@ module Arel
describe 'order' do
it 'generates order clauses' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Nodes::SqlLiteral.new '*'
manager.from table
manager.order table[:id]
@@ -438,7 +436,7 @@ module Arel
# FIXME: I would like to deprecate this
it 'takes *args' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Nodes::SqlLiteral.new '*'
manager.from table
manager.order table[:id], table[:name]
@@ -449,13 +447,13 @@ module Arel
it 'chains' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.order(table[:id]).must_equal manager
end
it 'has order attributes' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Nodes::SqlLiteral.new '*'
manager.from table
manager.order table[:id].desc
@@ -470,7 +468,7 @@ module Arel
left = Table.new :users
right = left.alias
predicate = left[:id].eq(right[:id])
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from left
manager.join(right).on(predicate, predicate)
@@ -486,7 +484,7 @@ module Arel
left = Table.new :users
right = left.alias
predicate = left[:id].eq(right[:id])
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from left
manager.join(right).on(
@@ -505,12 +503,12 @@ module Arel
end
it 'should hand back froms' do
- relation = Arel::SelectManager.new Table.engine
+ relation = Arel::SelectManager.new
assert_equal [], relation.froms
end
it 'should create and nodes' do
- relation = Arel::SelectManager.new Table.engine
+ relation = Arel::SelectManager.new
children = ['foo', 'bar', 'baz']
clause = relation.create_and children
assert_kind_of Arel::Nodes::And, clause
@@ -518,13 +516,13 @@ module Arel
end
it 'should create insert managers' do
- relation = Arel::SelectManager.new Table.engine
+ relation = Arel::SelectManager.new
insert = relation.create_insert
assert_kind_of Arel::InsertManager, insert
end
it 'should create join nodes' do
- relation = Arel::SelectManager.new Table.engine
+ relation = Arel::SelectManager.new
join = relation.create_join 'foo', 'bar'
assert_kind_of Arel::Nodes::InnerJoin, join
assert_equal 'foo', join.left
@@ -532,7 +530,7 @@ module Arel
end
it 'should create join nodes with a full outer join klass' do
- relation = Arel::SelectManager.new Table.engine
+ relation = Arel::SelectManager.new
join = relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin
assert_kind_of Arel::Nodes::FullOuterJoin, join
assert_equal 'foo', join.left
@@ -540,7 +538,7 @@ module Arel
end
it 'should create join nodes with a outer join klass' do
- relation = Arel::SelectManager.new Table.engine
+ relation = Arel::SelectManager.new
join = relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin
assert_kind_of Arel::Nodes::OuterJoin, join
assert_equal 'foo', join.left
@@ -548,7 +546,7 @@ module Arel
end
it 'should create join nodes with a right outer join klass' do
- relation = Arel::SelectManager.new Table.engine
+ relation = Arel::SelectManager.new
join = relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin
assert_kind_of Arel::Nodes::RightOuterJoin, join
assert_equal 'foo', join.left
@@ -560,7 +558,7 @@ module Arel
left = Table.new :users
right = left.alias
predicate = left[:id].eq(right[:id])
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from left
manager.join(right).on(predicate)
@@ -575,7 +573,7 @@ module Arel
left = Table.new :users
right = left.alias
predicate = left[:id].eq(right[:id])
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from left
manager.join(right, Nodes::OuterJoin).on(predicate)
@@ -586,8 +584,38 @@ module Arel
}
end
+ it 'takes the full outer join class' do
+ left = Table.new :users
+ right = left.alias
+ predicate = left[:id].eq(right[:id])
+ manager = Arel::SelectManager.new
+
+ manager.from left
+ manager.join(right, Nodes::FullOuterJoin).on(predicate)
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users"
+ FULL OUTER JOIN "users" "users_2"
+ ON "users"."id" = "users_2"."id"
+ }
+ end
+
+ it 'takes the right outer join class' do
+ left = Table.new :users
+ right = left.alias
+ predicate = left[:id].eq(right[:id])
+ manager = Arel::SelectManager.new
+
+ manager.from left
+ manager.join(right, Nodes::RightOuterJoin).on(predicate)
+ manager.to_sql.must_be_like %{
+ SELECT FROM "users"
+ RIGHT OUTER JOIN "users" "users_2"
+ ON "users"."id" = "users_2"."id"
+ }
+ end
+
it 'noops on nil' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.join(nil).must_equal manager
end
end
@@ -597,7 +625,7 @@ module Arel
left = Table.new :users
right = left.alias
predicate = left[:id].eq(right[:id])
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from left
manager.outer_join(right).on(predicate)
@@ -609,7 +637,7 @@ module Arel
end
it 'noops on nil' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.outer_join(nil).must_equal manager
end
end
@@ -619,7 +647,7 @@ module Arel
it 'returns inner join sql' do
table = Table.new :users
aliaz = table.alias
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from Nodes::InnerJoin.new(aliaz, table[:id].eq(aliaz[:id]))
assert_match 'INNER JOIN "users" "users_2" "users"."id" = "users_2"."id"',
manager.to_sql
@@ -628,7 +656,7 @@ module Arel
it 'returns outer join sql' do
table = Table.new :users
aliaz = table.alias
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from Nodes::OuterJoin.new(aliaz, table[:id].eq(aliaz[:id]))
assert_match 'LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id"',
manager.to_sql
@@ -638,7 +666,7 @@ module Arel
users = Table.new :users
comments = Table.new :comments
- counts = comments.from(comments).
+ counts = comments.from.
group(comments[:user_id]).
project(
comments[:user_id].as("user_id"),
@@ -668,7 +696,7 @@ module Arel
end
it 'returns string join sql' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from Nodes::StringJoin.new(Nodes.build_quoted('hello'))
assert_match "'hello'", manager.to_sql
end
@@ -677,7 +705,7 @@ module Arel
describe 'group' do
it 'takes an attribute' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.group table[:id]
manager.to_sql.must_be_like %{
@@ -687,13 +715,13 @@ module Arel
it 'chains' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.group(table[:id]).must_equal manager
end
it 'takes multiple args' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.group table[:id], table[:name]
manager.to_sql.must_be_like %{
@@ -704,7 +732,7 @@ module Arel
# FIXME: backwards compat
it 'makes strings literals' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.group 'foo'
manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo }
@@ -714,7 +742,7 @@ module Arel
describe 'window definition' do
it 'can be empty' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window')
manager.to_sql.must_be_like %{
@@ -724,7 +752,7 @@ module Arel
it 'takes an order' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').order(table['foo'].asc)
manager.to_sql.must_be_like %{
@@ -734,7 +762,7 @@ module Arel
it 'takes an order with multiple columns' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').order(table['foo'].asc, table['bar'].desc)
manager.to_sql.must_be_like %{
@@ -744,7 +772,7 @@ module Arel
it 'takes a partition' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').partition(table['bar'])
manager.to_sql.must_be_like %{
@@ -754,7 +782,7 @@ module Arel
it 'takes a partition and an order' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').partition(table['foo']).order(table['foo'].asc)
manager.to_sql.must_be_like %{
@@ -765,7 +793,7 @@ module Arel
it 'takes a partition with multiple columns' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').partition(table['bar'], table['baz'])
manager.to_sql.must_be_like %{
@@ -775,7 +803,7 @@ module Arel
it 'takes a rows frame, unbounded preceding' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').rows(Arel::Nodes::Preceding.new)
manager.to_sql.must_be_like %{
@@ -785,7 +813,7 @@ module Arel
it 'takes a rows frame, bounded preceding' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').rows(Arel::Nodes::Preceding.new(5))
manager.to_sql.must_be_like %{
@@ -795,7 +823,7 @@ module Arel
it 'takes a rows frame, unbounded following' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').rows(Arel::Nodes::Following.new)
manager.to_sql.must_be_like %{
@@ -805,7 +833,7 @@ module Arel
it 'takes a rows frame, bounded following' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').rows(Arel::Nodes::Following.new(5))
manager.to_sql.must_be_like %{
@@ -815,7 +843,7 @@ module Arel
it 'takes a rows frame, current row' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').rows(Arel::Nodes::CurrentRow.new)
manager.to_sql.must_be_like %{
@@ -825,7 +853,7 @@ module Arel
it 'takes a rows frame, between two delimiters' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
window = manager.window('a_window')
window.frame(
@@ -842,7 +870,7 @@ module Arel
it 'takes a range frame, unbounded preceding' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').range(Arel::Nodes::Preceding.new)
manager.to_sql.must_be_like %{
@@ -852,7 +880,7 @@ module Arel
it 'takes a range frame, bounded preceding' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').range(Arel::Nodes::Preceding.new(5))
manager.to_sql.must_be_like %{
@@ -862,7 +890,7 @@ module Arel
it 'takes a range frame, unbounded following' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').range(Arel::Nodes::Following.new)
manager.to_sql.must_be_like %{
@@ -872,7 +900,7 @@ module Arel
it 'takes a range frame, bounded following' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').range(Arel::Nodes::Following.new(5))
manager.to_sql.must_be_like %{
@@ -882,7 +910,7 @@ module Arel
it 'takes a range frame, current row' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.window('a_window').range(Arel::Nodes::CurrentRow.new)
manager.to_sql.must_be_like %{
@@ -892,7 +920,7 @@ module Arel
it 'takes a range frame, between two delimiters' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
window = manager.window('a_window')
window.frame(
@@ -911,7 +939,7 @@ module Arel
describe 'delete' do
it "copies from" do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
stmt = manager.compile_delete
@@ -920,7 +948,7 @@ module Arel
it "copies where" do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.where table[:id].eq 10
stmt = manager.compile_delete
@@ -934,7 +962,7 @@ module Arel
describe 'where_sql' do
it 'gives me back the where sql' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.where table[:id].eq 10
manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 }
@@ -942,7 +970,7 @@ module Arel
it 'returns nil when there are no wheres' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.where_sql.must_be_nil
end
@@ -952,7 +980,7 @@ module Arel
it 'creates an update statement' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id'))
@@ -963,7 +991,7 @@ module Arel
it 'takes a string' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id'))
@@ -972,7 +1000,7 @@ module Arel
it 'copies limits' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.take 1
stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id'))
@@ -986,7 +1014,7 @@ module Arel
it 'copies order' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.order :foo
stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id'))
@@ -1000,7 +1028,7 @@ module Arel
it 'copies where clauses' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.where table[:id].eq 10
manager.from table
stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id'))
@@ -1012,7 +1040,7 @@ module Arel
it 'copies where clauses when nesting is triggered' do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.where table[:foo].eq 10
manager.take 42
manager.from table
@@ -1027,20 +1055,20 @@ module Arel
describe 'project' do
it "takes sql literals" do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Nodes::SqlLiteral.new '*'
manager.to_sql.must_be_like %{ SELECT * }
end
it 'takes multiple args' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Nodes::SqlLiteral.new('foo'),
Nodes::SqlLiteral.new('bar')
manager.to_sql.must_be_like %{ SELECT foo, bar }
end
it 'takes strings' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project '*'
manager.to_sql.must_be_like %{ SELECT * }
end
@@ -1049,7 +1077,7 @@ module Arel
describe 'projections' do
it 'reads projections' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Arel.sql('foo'), Arel.sql('bar')
manager.projections.must_equal [Arel.sql('foo'), Arel.sql('bar')]
end
@@ -1057,7 +1085,7 @@ module Arel
describe 'projections=' do
it 'overwrites projections' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.project Arel.sql('foo')
manager.projections = [Arel.sql('bar')]
manager.to_sql.must_be_like %{ SELECT bar }
@@ -1067,7 +1095,7 @@ module Arel
describe 'take' do
it "knows take" do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from(table).project(table['id'])
manager.where(table['id'].eq(1))
manager.take 1
@@ -1081,12 +1109,12 @@ module Arel
end
it "chains" do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.take(1).must_equal manager
end
it 'removes LIMIT when nil is passed' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.limit = 10
assert_match('LIMIT', manager.to_sql)
@@ -1098,7 +1126,7 @@ module Arel
describe 'where' do
it "knows where" do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from(table).project(table['id'])
manager.where(table['id'].eq(1))
manager.to_sql.must_be_like %{
@@ -1110,7 +1138,7 @@ module Arel
it "chains" do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from(table)
manager.project(table['id']).where(table['id'].eq 1).must_equal manager
end
@@ -1119,7 +1147,7 @@ module Arel
describe 'from' do
it "makes sql" do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from table
manager.project table['id']
@@ -1128,7 +1156,7 @@ module Arel
it "chains" do
table = Table.new :users
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.from(table).project(table['id']).must_equal manager
manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"'
end
@@ -1136,14 +1164,14 @@ module Arel
describe 'source' do
it 'returns the join source of the select core' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.source.must_equal manager.ast.cores.last.source
end
end
describe 'distinct' do
it 'sets the quantifier' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.distinct
manager.ast.cores.last.set_quantifier.class.must_equal Arel::Nodes::Distinct
@@ -1153,7 +1181,7 @@ module Arel
end
it "chains" do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
manager.distinct.must_equal manager
manager.distinct(false).must_equal manager
end
@@ -1161,7 +1189,7 @@ module Arel
describe 'distinct_on' do
it 'sets the quantifier' do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
table = Table.new :users
manager.distinct_on(table['id'])
@@ -1172,7 +1200,7 @@ module Arel
end
it "chains" do
- manager = Arel::SelectManager.new Table.engine
+ manager = Arel::SelectManager.new
table = Table.new :users
manager.distinct_on(table['id']).must_equal manager
diff --git a/test/test_table.rb b/test/test_table.rb
index 14256475ec..e8eaf901cc 100644
--- a/test/test_table.rb
+++ b/test/test_table.rb
@@ -47,12 +47,6 @@ module Arel
assert_equal "INSERT INTO \"users\" VALUES(NULL)", im.to_sql
end
- it 'should return IM from insert_manager' do
- im = @relation.insert_manager
- assert_kind_of Arel::InsertManager, im
- assert_equal im.engine, @relation.engine
- end
-
describe 'skip' do
it 'should add an offset' do
sm = @relation.skip 2
@@ -60,29 +54,6 @@ module Arel
end
end
- describe 'select_manager' do
- it 'should return an empty select manager' do
- sm = @relation.select_manager
- sm.to_sql.must_be_like 'SELECT'
- end
- end
-
- describe 'update_manager' do
- it 'should return an update manager' do
- um = @relation.update_manager
- assert_kind_of Arel::UpdateManager, um
- assert_equal um.engine, @relation.engine
- end
- end
-
- describe 'delete_manager' do
- it 'should return a delete manager' do
- dm = @relation.delete_manager
- assert_kind_of Arel::DeleteManager, dm
- assert_equal dm.engine, @relation.engine
- end
- end
-
describe 'having' do
it 'adds a having clause' do
mgr = @relation.having @relation[:id].eq(10)
@@ -149,14 +120,9 @@ module Arel
end
describe 'new' do
- it 'should accept an engine' do
- rel = Table.new :users, 'foo'
- rel.engine.must_equal 'foo'
- end
-
it 'should accept a hash' do
- rel = Table.new :users, :engine => 'foo'
- rel.engine.must_equal 'foo'
+ rel = Table.new :users, :as => 'foo'
+ rel.table_alias.must_equal 'foo'
end
it 'ignores as if it equals name' do
@@ -213,10 +179,6 @@ module Arel
@relation.table_name.must_equal 'users'
end
- it "should have an engine" do
- @relation.engine.must_equal Table.engine
- end
-
describe '[]' do
describe 'when given a Symbol' do
it "manufactures an attribute if the symbol names an attribute within the relation" do
@@ -228,10 +190,10 @@ module Arel
describe 'equality' do
it 'is equal with equal ivars' do
- relation1 = Table.new(:users, 'vroom')
+ relation1 = Table.new(:users)
relation1.aliases = %w[a b c]
relation1.table_alias = 'zomg'
- relation2 = Table.new(:users, 'vroom')
+ relation2 = Table.new(:users)
relation2.aliases = %w[a b c]
relation2.table_alias = 'zomg'
array = [relation1, relation2]
@@ -239,10 +201,10 @@ module Arel
end
it 'is not equal with different ivars' do
- relation1 = Table.new(:users, 'vroom')
+ relation1 = Table.new(:users)
relation1.aliases = %w[a b c]
relation1.table_alias = 'zomg'
- relation2 = Table.new(:users, 'vroom')
+ relation2 = Table.new(:users)
relation2.aliases = %w[x y z]
relation2.table_alias = 'zomg'
array = [relation1, relation2]
diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb
index f1a019970d..f41dc46e7d 100644
--- a/test/test_update_manager.rb
+++ b/test/test_update_manager.rb
@@ -4,21 +4,21 @@ module Arel
describe 'update manager' do
describe 'new' do
it 'takes an engine' do
- Arel::UpdateManager.new Table.engine
+ Arel::UpdateManager.new
end
end
it "should not quote sql literals" do
table = Table.new(:users)
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.table table
- um.set [[table[:name], (Arel::Nodes::BindParam.new '?')]]
+ um.set [[table[:name], Arel::Nodes::BindParam.new]]
um.to_sql.must_be_like %{ UPDATE "users" SET "name" = ? }
end
it 'handles limit properly' do
table = Table.new(:users)
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.key = 'id'
um.take 10
um.table table
@@ -29,7 +29,7 @@ module Arel
describe 'set' do
it "updates with null" do
table = Table.new(:users)
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.table table
um.set [[table[:name], nil]]
um.to_sql.must_be_like %{ UPDATE "users" SET "name" = NULL }
@@ -37,7 +37,7 @@ module Arel
it 'takes a string' do
table = Table.new(:users)
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.table table
um.set Nodes::SqlLiteral.new "foo = bar"
um.to_sql.must_be_like %{ UPDATE "users" SET foo = bar }
@@ -45,7 +45,7 @@ module Arel
it 'takes a list of lists' do
table = Table.new(:users)
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.table table
um.set [[table[:id], 1], [table[:name], 'hello']]
um.to_sql.must_be_like %{
@@ -55,25 +55,25 @@ module Arel
it 'chains' do
table = Table.new(:users)
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.set([[table[:id], 1], [table[:name], 'hello']]).must_equal um
end
end
describe 'table' do
it 'generates an update statement' do
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.table Table.new(:users)
um.to_sql.must_be_like %{ UPDATE "users" }
end
it 'chains' do
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.table(Table.new(:users)).must_equal um
end
it 'generates an update statement with joins' do
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
table = Table.new(:users)
join_source = Arel::Nodes::JoinSource.new(
@@ -89,7 +89,7 @@ module Arel
describe 'where' do
it 'generates a where clause' do
table = Table.new :users
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.table table
um.where table[:id].eq(1)
um.to_sql.must_be_like %{
@@ -99,7 +99,7 @@ module Arel
it 'chains' do
table = Table.new :users
- um = Arel::UpdateManager.new Table.engine
+ um = Arel::UpdateManager.new
um.table table
um.where(table[:id].eq(1)).must_equal um
end
@@ -108,7 +108,7 @@ module Arel
describe 'key' do
before do
@table = Table.new :users
- @um = Arel::UpdateManager.new Table.engine
+ @um = Arel::UpdateManager.new
@um.key = @table[:foo]
end
diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb
index 333636ed51..f0007cabbf 100644
--- a/test/visitors/test_bind_visitor.rb
+++ b/test/visitors/test_bind_visitor.rb
@@ -17,8 +17,8 @@ module Arel
# substitutes binds with values from block
def test_assignment_binds_are_substituted
table = Table.new(:users)
- um = Arel::UpdateManager.new Table.engine
- bp = Nodes::BindParam.new '?'
+ um = Arel::UpdateManager.new
+ bp = Nodes::BindParam.new
um.set [[table[:name], bp]]
visitor = Class.new(Arel::Visitors::ToSql) {
include Arel::Visitors::BindVisitor
@@ -38,7 +38,7 @@ module Arel
include Arel::Visitors::BindVisitor
}.new nil
- bp = Nodes::BindParam.new 'omg'
+ bp = Nodes::BindParam.new
called = false
visitor.accept(bp, collector) { called = true }
assert called
diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb
index d50ea3e59a..3356759b7d 100644
--- a/test/visitors/test_depth_first.rb
+++ b/test/visitors/test_depth_first.rb
@@ -30,7 +30,6 @@ module Arel
Arel::Nodes::Grouping,
Arel::Nodes::Offset,
Arel::Nodes::Ordering,
- Arel::Nodes::Having,
Arel::Nodes::StringJoin,
Arel::Nodes::UnqualifiedColumn,
Arel::Nodes::Top,
@@ -206,7 +205,7 @@ module Arel
core.wheres << :c
core.groups << :d
core.windows << :e
- core.having = :f
+ core.havings << :f
@visitor.accept core
assert_equal [
@@ -216,7 +215,7 @@ module Arel
:c, core.wheres,
:d, core.groups,
:e, core.windows,
- :f,
+ :f, core.havings,
core], @collector.calls
end
diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb
index 7763350f5c..4dc3c9c6c5 100644
--- a/test/visitors/test_dot.rb
+++ b/test/visitors/test_dot.rb
@@ -34,7 +34,6 @@ module Arel
Arel::Nodes::Grouping,
Arel::Nodes::Offset,
Arel::Nodes::Ordering,
- Arel::Nodes::Having,
Arel::Nodes::UnqualifiedColumn,
Arel::Nodes::Top,
Arel::Nodes::Limit,
diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb
index a3efcb8b27..fe228bce4b 100644
--- a/test/visitors/test_mssql.rb
+++ b/test/visitors/test_mssql.rb
@@ -26,6 +26,34 @@ module Arel
sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY \"users\".\"id\") as _row_num FROM \"users\") as _t WHERE _row_num BETWEEN 1 AND 10"
end
+ it 'caches the PK lookup for order' do
+ connection = MiniTest::Mock.new
+ connection.expect(:primary_key, ["id"], ["users"])
+
+ # We don't care how many times these methods are called
+ def connection.quote_table_name(*); ""; end
+ def connection.quote_column_name(*); ""; end
+
+ @visitor = MSSQL.new(connection)
+ stmt = Nodes::SelectStatement.new
+ stmt.cores.first.from = @table
+ stmt.limit = Nodes::Limit.new(10)
+
+ compile(stmt)
+ compile(stmt)
+
+ connection.verify
+ end
+
+ it 'should use TOP for limited deletes' do
+ stmt = Nodes::DeleteStatement.new
+ stmt.relation = @table
+ stmt.limit = Nodes::Limit.new(10)
+ sql = compile(stmt)
+
+ sql.must_be_like "DELETE TOP (10) FROM \"users\""
+ end
+
it 'should go over query ORDER BY if .order()' do
stmt = Nodes::SelectStatement.new
stmt.limit = Nodes::Limit.new(10)
diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb
index 29d7042084..e9ed9d76b3 100644
--- a/test/visitors/test_oracle.rb
+++ b/test/visitors/test_oracle.rb
@@ -4,7 +4,8 @@ module Arel
module Visitors
describe 'the oracle visitor' do
before do
- @visitor = Oracle.new Table.engine.connection_pool
+ @visitor = Oracle.new Table.engine.connection
+ @table = Table.new(:users)
end
def compile node
@@ -110,7 +111,7 @@ module Arel
it 'creates a different subquery when there is an offset' do
stmt = Nodes::SelectStatement.new
- stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10))
+ stmt.limit = Nodes::Limit.new(10)
stmt.offset = Nodes::Offset.new(10)
sql = compile stmt
sql.must_be_like %{
@@ -125,7 +126,7 @@ module Arel
it 'is idempotent with different subquery' do
stmt = Nodes::SelectStatement.new
- stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10))
+ stmt.limit = Nodes::Limit.new(10)
stmt.offset = Nodes::Offset.new(10)
sql = compile stmt
sql2 = compile stmt
@@ -165,6 +166,16 @@ module Arel
compile(node).must_be_like "FOR UPDATE"
end
end
+
+ describe "Nodes::BindParam" do
+ it "increments each bind param" do
+ query = @table[:name].eq(Arel::Nodes::BindParam.new)
+ .and(@table[:id].eq(Arel::Nodes::BindParam.new))
+ compile(query).must_be_like %{
+ "users"."name" = :a1 AND "users"."id" = :a2
+ }
+ end
+ end
end
end
end
diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb
new file mode 100644
index 0000000000..df0f01b30b
--- /dev/null
+++ b/test/visitors/test_oracle12.rb
@@ -0,0 +1,47 @@
+require 'helper'
+
+module Arel
+ module Visitors
+ describe 'the oracle visitor' do
+ before do
+ @visitor = Oracle12.new Table.engine.connection_pool
+ end
+
+ def compile node
+ @visitor.accept(node, Collectors::SQLString.new).value
+ end
+
+ it 'modified except to be minus' do
+ left = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 10")
+ right = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 20")
+ sql = compile Nodes::Except.new(left, right)
+ sql.must_be_like %{
+ ( SELECT * FROM users WHERE age > 10 MINUS SELECT * FROM users WHERE age > 20 )
+ }
+ end
+
+ it 'generates select options offset then limit' do
+ stmt = Nodes::SelectStatement.new
+ stmt.offset = Nodes::Offset.new(1)
+ stmt.limit = Nodes::Limit.new(10)
+ sql = compile(stmt)
+ sql.must_be_like "SELECT OFFSET 1 ROWS FETCH FIRST 10 ROWS ONLY"
+ end
+
+ describe 'locking' do
+ it 'removes limit when locking' do
+ stmt = Nodes::SelectStatement.new
+ stmt.limit = Nodes::Limit.new(10)
+ stmt.lock = Nodes::Lock.new(Arel.sql('FOR UPDATE'))
+ sql = compile(stmt)
+ sql.must_be_like "SELECT FOR UPDATE"
+ end
+
+ it 'defaults to FOR UPDATE when locking' do
+ node = Nodes::Lock.new(Arel.sql('FOR UPDATE'))
+ compile(node).must_be_like "FOR UPDATE"
+ end
+ end
+ end
+ end
+end
diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb
index 3d646a7324..4b7dbe367f 100644
--- a/test/visitors/test_postgres.rb
+++ b/test/visitors/test_postgres.rb
@@ -53,11 +53,28 @@ module Arel
describe "Nodes::Matches" do
it "should know how to visit" do
node = @table[:name].matches('foo%')
+ node.must_be_kind_of Nodes::Matches
+ node.case_sensitive.must_equal(false)
compile(node).must_be_like %{
"users"."name" ILIKE 'foo%'
}
end
+ it "should know how to visit case sensitive" do
+ node = @table[:name].matches('foo%', nil, true)
+ node.case_sensitive.must_equal(true)
+ compile(node).must_be_like %{
+ "users"."name" LIKE 'foo%'
+ }
+ end
+
+ it "can handle ESCAPE" do
+ node = @table[:name].matches('foo!%', '!')
+ compile(node).must_be_like %{
+ "users"."name" ILIKE 'foo!%' ESCAPE '!'
+ }
+ end
+
it 'can handle subqueries' do
subquery = @table.project(:id).where(@table[:name].matches('foo%'))
node = @attr.in subquery
@@ -70,11 +87,28 @@ module Arel
describe "Nodes::DoesNotMatch" do
it "should know how to visit" do
node = @table[:name].does_not_match('foo%')
+ node.must_be_kind_of Nodes::DoesNotMatch
+ node.case_sensitive.must_equal(false)
compile(node).must_be_like %{
"users"."name" NOT ILIKE 'foo%'
}
end
+ it "should know how to visit case sensitive" do
+ node = @table[:name].does_not_match('foo%', nil, true)
+ node.case_sensitive.must_equal(true)
+ compile(node).must_be_like %{
+ "users"."name" NOT LIKE 'foo%'
+ }
+ end
+
+ it "can handle ESCAPE" do
+ node = @table[:name].does_not_match('foo!%', '!')
+ compile(node).must_be_like %{
+ "users"."name" NOT ILIKE 'foo!%' ESCAPE '!'
+ }
+ end
+
it 'can handle subqueries' do
subquery = @table.project(:id).where(@table[:name].does_not_match('foo%'))
node = @attr.in subquery
@@ -86,34 +120,65 @@ module Arel
describe "Nodes::Regexp" do
it "should know how to visit" do
- node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'))
+ node = @table[:name].matches_regexp('foo.*')
+ node.must_be_kind_of Nodes::Regexp
+ node.case_sensitive.must_equal(true)
compile(node).must_be_like %{
- "users"."name" ~ 'foo%'
+ "users"."name" ~ 'foo.*'
+ }
+ end
+
+ it "can handle case insensitive" do
+ node = @table[:name].matches_regexp('foo.*', false)
+ node.must_be_kind_of Nodes::Regexp
+ node.case_sensitive.must_equal(false)
+ compile(node).must_be_like %{
+ "users"."name" ~* 'foo.*'
}
end
it 'can handle subqueries' do
- subquery = @table.project(:id).where(Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')))
+ subquery = @table.project(:id).where(@table[:name].matches_regexp('foo.*'))
node = @attr.in subquery
compile(node).must_be_like %{
- "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo%')
+ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo.*')
}
end
end
describe "Nodes::NotRegexp" do
it "should know how to visit" do
- node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'))
+ node = @table[:name].does_not_match_regexp('foo.*')
+ node.must_be_kind_of Nodes::NotRegexp
+ node.case_sensitive.must_equal(true)
+ compile(node).must_be_like %{
+ "users"."name" !~ 'foo.*'
+ }
+ end
+
+ it "can handle case insensitive" do
+ node = @table[:name].does_not_match_regexp('foo.*', false)
+ node.case_sensitive.must_equal(false)
compile(node).must_be_like %{
- "users"."name" !~ 'foo%'
+ "users"."name" !~* 'foo.*'
}
end
it 'can handle subqueries' do
- subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')))
+ subquery = @table.project(:id).where(@table[:name].does_not_match_regexp('foo.*'))
node = @attr.in subquery
compile(node).must_be_like %{
- "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo%')
+ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo.*')
+ }
+ end
+ end
+
+ describe "Nodes::BindParam" do
+ it "increments each bind param" do
+ query = @table[:name].eq(Arel::Nodes::BindParam.new)
+ .and(@table[:id].eq(Arel::Nodes::BindParam.new))
+ compile(query).must_be_like %{
+ "users"."name" = $1 AND "users"."id" = $2
}
end
end
diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb
index abd8cfe356..7ae5d5b3af 100644
--- a/test/visitors/test_to_sql.rb
+++ b/test/visitors/test_to_sql.rb
@@ -16,9 +16,16 @@ module Arel
end
it 'works with BindParams' do
- node = Nodes::BindParam.new 'omg'
+ node = Nodes::BindParam.new
sql = compile node
- sql.must_be_like 'omg'
+ sql.must_be_like '?'
+ end
+
+ it 'does not quote BindParams used as part of a Values' do
+ bp = Nodes::BindParam.new
+ values = Nodes::Values.new([bp])
+ sql = compile values
+ sql.must_be_like 'VALUES (?)'
end
it 'can define a dispatch method' do
@@ -29,7 +36,7 @@ module Arel
end
def dispatch
- { Arel::Table.name => 'hello' }
+ { Arel::Table => 'hello' }
end
}.new
@@ -174,6 +181,13 @@ module Arel
assert_match(/LIMIT 'omg'/, compile(sc))
end
+ it "should contain a single space before ORDER BY" do
+ table = Table.new(:users)
+ test = table.order(table[:name])
+ sql = compile test
+ assert_match(/"users" ORDER BY/, sql)
+ end
+
it "should quote LIMIT without column type coercion" do
table = Table.new(:users)
sc = table.where(table[:name].eq(0)).take(1).ast
@@ -259,9 +273,9 @@ module Arel
compile(Nodes.build_quoted(nil)).must_be_like "NULL"
end
- it "unsupported input should not raise ArgumentError" do
- error = assert_raises(RuntimeError) { compile(nil) }
- assert_match(/\Aunsupported/, error.message)
+ it "unsupported input should raise UnsupportedVisitError" do
+ error = assert_raises(UnsupportedVisitError) { compile(nil) }
+ assert_match(/\AUnsupported/, error.message)
end
it "should visit_Arel_SelectManager, which is a subquery" do
@@ -284,7 +298,7 @@ module Arel
end
it "should visit_Arel_Nodes_Assignment" do
- column = @table["id"]
+ column = @table["id"]
node = Nodes::Assignment.new(
Nodes::UnqualifiedColumn.new(column),
Nodes::UnqualifiedColumn.new(column)
@@ -375,33 +389,33 @@ module Arel
end
it 'can handle two dot ranges' do
- node = @attr.in 1..3
+ node = @attr.between 1..3
compile(node).must_be_like %{
"users"."id" BETWEEN 1 AND 3
}
end
it 'can handle three dot ranges' do
- node = @attr.in 1...3
+ node = @attr.between 1...3
compile(node).must_be_like %{
"users"."id" >= 1 AND "users"."id" < 3
}
end
it 'can handle ranges bounded by infinity' do
- node = @attr.in 1..Float::INFINITY
+ node = @attr.between 1..Float::INFINITY
compile(node).must_be_like %{
"users"."id" >= 1
}
- node = @attr.in(-Float::INFINITY..3)
+ node = @attr.between(-Float::INFINITY..3)
compile(node).must_be_like %{
"users"."id" <= 3
}
- node = @attr.in(-Float::INFINITY...3)
+ node = @attr.between(-Float::INFINITY...3)
compile(node).must_be_like %{
"users"."id" < 3
}
- node = @attr.in(-Float::INFINITY..Float::INFINITY)
+ node = @attr.between(-Float::INFINITY..Float::INFINITY)
compile(node).must_be_like %{1=1}
end
@@ -479,33 +493,33 @@ module Arel
end
it 'can handle two dot ranges' do
- node = @attr.not_in 1..3
- compile(node).must_be_like %{
- "users"."id" < 1 OR "users"."id" > 3
- }
+ node = @attr.not_between 1..3
+ compile(node).must_equal(
+ %{("users"."id" < 1 OR "users"."id" > 3)}
+ )
end
it 'can handle three dot ranges' do
- node = @attr.not_in 1...3
- compile(node).must_be_like %{
- "users"."id" < 1 OR "users"."id" >= 3
- }
+ node = @attr.not_between 1...3
+ compile(node).must_equal(
+ %{("users"."id" < 1 OR "users"."id" >= 3)}
+ )
end
it 'can handle ranges bounded by infinity' do
- node = @attr.not_in 1..Float::INFINITY
+ node = @attr.not_between 1..Float::INFINITY
compile(node).must_be_like %{
"users"."id" < 1
}
- node = @attr.not_in(-Float::INFINITY..3)
+ node = @attr.not_between(-Float::INFINITY..3)
compile(node).must_be_like %{
"users"."id" > 3
}
- node = @attr.not_in(-Float::INFINITY...3)
+ node = @attr.not_between(-Float::INFINITY...3)
compile(node).must_be_like %{
"users"."id" >= 3
}
- node = @attr.not_in(-Float::INFINITY..Float::INFINITY)
+ node = @attr.not_between(-Float::INFINITY..Float::INFINITY)
compile(node).must_be_like %{1=0}
end