diff -Nru ruby-arel-6.0.3/arel.gemspec ruby-arel-6.0.4/arel.gemspec --- ruby-arel-6.0.3/arel.gemspec 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/arel.gemspec 2016-12-27 13:51:36.000000000 +0000 @@ -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 = ["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/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/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"] + + s.add_development_dependency('minitest', '~> 5.4') + s.add_development_dependency('rdoc', '~> 4.0') + s.add_development_dependency('rake') +end diff -Nru ruby-arel-6.0.3/arel.gemspec.erb ruby-arel-6.0.4/arel.gemspec.erb --- ruby-arel-6.0.3/arel.gemspec.erb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/arel.gemspec.erb 2016-12-27 13:51:36.000000000 +0000 @@ -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 -Nru ruby-arel-6.0.3/debian/changelog ruby-arel-6.0.4/debian/changelog --- ruby-arel-6.0.3/debian/changelog 2015-12-12 18:10:02.000000000 +0000 +++ ruby-arel-6.0.4/debian/changelog 2018-02-10 01:04:37.000000000 +0000 @@ -1,3 +1,33 @@ +ruby-arel (6.0.4-1) unstable; urgency=medium + + [ Georg Faerber ] + * New upstream release. + * debian/changelog: Remove trailing whitespaces. + * debian/compat: Bump debhelper compatibility level to 11. + * debian/control: + - Bump Standards-Version to 4.1.3, no changes needed. + - Use debian-ruby@lists.debian.org in Maintainer field. + - Use salsa.debian.org in Vcs-Browser and Vcs-Git fields, as + anonscm.debian.org is deprecated and accordingly, all repositories were + moved. + - Add myself as uploader. + - Use HTTPS for Homepage field. + - Bump debhelper version to >= 11~. + - Drop obsolete declaration that this package breaks with + ruby-activerecord-3.2. Lintian did complain about this, as no version + was specified. Moreover, ruby-activerecord-3.2 is only available in + oldoldstable, a suite this package will never migrate to. + * debian/copyright: Update authors and use HTTPS in links. + * debian/tests/control: Add control file to enable running the upstream test + suite via autopkgtest. + + [ Cédric Boutillier ] + * debian/control: + - Run wrap-and-sort on packaging files. + - Remove version in the gem2deb build-dependency. + + -- Georg Faerber Sat, 10 Feb 2018 02:04:37 +0100 + ruby-arel (6.0.3-2) unstable; urgency=medium * Upload to unstable @@ -46,11 +76,11 @@ ruby-arel (4.0.0-1) unstable; urgency=low - * New upstream release + * New upstream release * Test suite added * Standards version changed to 3.9.4 * Docs installed - * Fixed missing upstream license + * Fixed missing upstream license -- Nitesh A Jain Tue, 02 Jul 2013 21:55:27 +0530 diff -Nru ruby-arel-6.0.3/debian/compat ruby-arel-6.0.4/debian/compat --- ruby-arel-6.0.3/debian/compat 2015-12-12 18:10:02.000000000 +0000 +++ ruby-arel-6.0.4/debian/compat 2018-02-10 01:04:37.000000000 +0000 @@ -1 +1 @@ -7 +11 diff -Nru ruby-arel-6.0.3/debian/control ruby-arel-6.0.4/debian/control --- ruby-arel-6.0.3/debian/control 2015-12-12 18:10:02.000000000 +0000 +++ ruby-arel-6.0.4/debian/control 2018-02-10 01:04:37.000000000 +0000 @@ -1,25 +1,25 @@ Source: ruby-arel Section: ruby Priority: optional -Maintainer: Debian Ruby Extras Maintainers -Uploaders: Nitesh A Jain -Build-Depends: debhelper (>= 7.0.50~), - gem2deb (>= 0.3.0~), - ruby-minitest (>= 5.3~), - ruby-hoe (>= 2.13~) -Standards-Version: 3.9.6 -Vcs-Git: git://anonscm.debian.org/pkg-ruby-extras/ruby-arel.git -Vcs-Browser: http://anonscm.debian.org/gitweb?p=pkg-ruby-extras/ruby-arel.git;a=summary -Homepage: http://github.com/rails/arel +Maintainer: Ruby packages maintenance +Uploaders: Georg Faerber , + Nitesh A Jain +Build-Depends: debhelper (>= 11~), + gem2deb, + ruby-hoe (>= 2.13~), + ruby-minitest (>= 5.3~) +Standards-Version: 4.1.3 +Vcs-Git: https://salsa.debian.org/ruby-team/ruby-arel.git +Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-arel +Homepage: https://github.com/rails/arel XS-Ruby-Versions: all Package: ruby-arel Architecture: all XB-Ruby-Versions: ${ruby:Versions} -Depends: ${shlibs:Depends}, - ${misc:Depends}, - ruby | ruby-interpreter -Breaks: ruby-activerecord-3.2 +Depends: ruby | ruby-interpreter, + ${misc:Depends}, + ${shlibs:Depends} Description: SQL AST manager for Ruby Arel is a SQL AST manager for Ruby. It simplifies the generation of complex SQL queries and adapts to various RDBMS systems. diff -Nru ruby-arel-6.0.3/debian/copyright ruby-arel-6.0.4/debian/copyright --- ruby-arel-6.0.3/debian/copyright 2015-12-12 18:10:02.000000000 +0000 +++ ruby-arel-6.0.4/debian/copyright 2018-02-10 01:04:37.000000000 +0000 @@ -1,17 +1,21 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: arel -Source: http://rubygems.org/gems/arel +Source: https://rubygems.org/gems/arel Files: * -Copyright: 2007-2011 Aaron Patterson - Bryan Halmkamp - Emilio Tagua - Nick Kallen +Copyright: 2007-2018 Aaron Patterson + Bryan Halmkamp + Emilio Tagua + Nick Kallen License: Expat Files: debian/* -Copyright: Copyright 2011 Ondřej Surý - 2013 Nitesh A Jain +Copyright: 2018 Georg Faerber + 2015 Praveen Arimbrathodiyil + 2013 Nitesh A Jain + 2013-2016 Cédric Boutillier + 2012-2015 Antonio Terceiro + 2011-2014 Ondřej Surý License: Expat License: Expat diff -Nru ruby-arel-6.0.3/debian/tests/control ruby-arel-6.0.4/debian/tests/control --- ruby-arel-6.0.3/debian/tests/control 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/debian/tests/control 2018-02-10 01:04:37.000000000 +0000 @@ -0,0 +1,2 @@ +Test-Command: gem2deb-test-runner --autopkgtest --check-dependencies 2>&1 +Depends: @, @builddeps@, gem2deb-test-runner diff -Nru ruby-arel-6.0.3/debian/watch ruby-arel-6.0.4/debian/watch --- ruby-arel-6.0.3/debian/watch 2015-12-12 18:10:02.000000000 +0000 +++ ruby-arel-6.0.4/debian/watch 2018-02-10 01:04:37.000000000 +0000 @@ -1,2 +1,2 @@ -version=3 -http://pkg-ruby-extras.alioth.debian.org/cgi-bin/gemwatch/arel .*/arel-(.*).tar.gz +version=4 +https://pkg-ruby-extras.alioth.debian.org/cgi-bin/gemwatch/arel .*/arel-(.*).tar.gz diff -Nru ruby-arel-6.0.3/Gemfile ruby-arel-6.0.4/Gemfile --- ruby-arel-6.0.3/Gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/Gemfile 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,3 @@ +source "https://rubygems.org/" + +gemspec diff -Nru ruby-arel-6.0.3/.gitignore ruby-arel-6.0.4/.gitignore --- ruby-arel-6.0.3/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/.gitignore 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,9 @@ +coverage/* +config/database.yml +spec/support/fixtures/*database* +*.DS_Store +debug.log +pkg +.bundle +*.swp +Gemfile.lock diff -Nru ruby-arel-6.0.3/History.txt ruby-arel-6.0.4/History.txt --- ruby-arel-6.0.3/History.txt 2015-08-13 21:51:00.000000000 +0000 +++ ruby-arel-6.0.4/History.txt 2016-12-27 13:51:36.000000000 +0000 @@ -1,3 +1,9 @@ +=== 6.0.4 / 2016-12-27 + +* Enhancements + + * Ruby 2.4 compatibility + === 6.0.3 / 2015-08-04 * Bug fixes diff -Nru ruby-arel-6.0.3/lib/arel/nodes/function.rb ruby-arel-6.0.4/lib/arel/nodes/function.rb --- ruby-arel-6.0.3/lib/arel/nodes/function.rb 2015-08-13 21:51:00.000000000 +0000 +++ ruby-arel-6.0.4/lib/arel/nodes/function.rb 2016-12-27 13:51:36.000000000 +0000 @@ -3,6 +3,7 @@ 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 -Nru ruby-arel-6.0.3/lib/arel/visitors/depth_first.rb ruby-arel-6.0.4/lib/arel/visitors/depth_first.rb --- ruby-arel-6.0.3/lib/arel/visitors/depth_first.rb 2015-08-13 21:51:00.000000000 +0000 +++ ruby-arel-6.0.4/lib/arel/visitors/depth_first.rb 2016-12-27 13:51:36.000000000 +0000 @@ -128,6 +128,7 @@ alias :visit_FalseClass :terminal alias :visit_Fixnum :terminal alias :visit_Float :terminal + alias :visit_Integer :terminal alias :visit_NilClass :terminal alias :visit_String :terminal alias :visit_Symbol :terminal diff -Nru ruby-arel-6.0.3/lib/arel/visitors/dot.rb ruby-arel-6.0.4/lib/arel/visitors/dot.rb --- ruby-arel-6.0.3/lib/arel/visitors/dot.rb 2015-08-13 21:51:00.000000000 +0000 +++ ruby-arel-6.0.4/lib/arel/visitors/dot.rb 2016-12-27 13:51:36.000000000 +0000 @@ -200,6 +200,7 @@ alias :visit_TrueClass :visit_String alias :visit_FalseClass :visit_String alias :visit_Arel_Nodes_BindParam :visit_String + alias :visit_Integer :visit_String alias :visit_Fixnum :visit_String alias :visit_BigDecimal :visit_String alias :visit_Float :visit_String diff -Nru ruby-arel-6.0.3/lib/arel/visitors/to_sql.rb ruby-arel-6.0.4/lib/arel/visitors/to_sql.rb --- ruby-arel-6.0.3/lib/arel/visitors/to_sql.rb 2015-08-13 21:51:00.000000000 +0000 +++ ruby-arel-6.0.4/lib/arel/visitors/to_sql.rb 2016-12-27 13:51:36.000000000 +0000 @@ -726,6 +726,7 @@ alias :visit_Arel_Nodes_SqlLiteral :literal alias :visit_Bignum :literal alias :visit_Fixnum :literal + alias :visit_Integer :literal def quoted o, a quote(o, column_for(a)) diff -Nru ruby-arel-6.0.3/lib/arel.rb ruby-arel-6.0.4/lib/arel.rb --- ruby-arel-6.0.3/lib/arel.rb 2015-08-13 21:51:00.000000000 +0000 +++ ruby-arel-6.0.4/lib/arel.rb 2016-12-27 13:51:36.000000000 +0000 @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '6.0.3' + VERSION = '6.0.4' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql diff -Nru ruby-arel-6.0.3/metadata.yml ruby-arel-6.0.4/metadata.yml --- ruby-arel-6.0.3/metadata.yml 2015-08-13 21:51:00.000000000 +0000 +++ ruby-arel-6.0.4/metadata.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,171 +0,0 @@ ---- !ruby/object:Gem::Specification -name: arel -version: !ruby/object:Gem::Version - version: 6.0.3 -platform: ruby -authors: -- Aaron Patterson -- Bryan Helmkamp -- Emilio Tagua -- Nick Kallen -autorequire: -bindir: bin -cert_chain: [] -date: 2015-08-04 00:00:00.000000000 Z -dependencies: -- !ruby/object:Gem::Dependency - name: minitest - requirement: !ruby/object:Gem::Requirement - requirements: - - - "~>" - - !ruby/object:Gem::Version - version: '5.4' - type: :development - prerelease: false - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - "~>" - - !ruby/object:Gem::Version - version: '5.4' -- !ruby/object:Gem::Dependency - name: rdoc - requirement: !ruby/object:Gem::Requirement - requirements: - - - "~>" - - !ruby/object:Gem::Version - version: '4.0' - type: :development - prerelease: false - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - "~>" - - !ruby/object:Gem::Version - version: '4.0' -description: |- - Arel Really Exasperates Logicians - - Arel is a SQL AST manager for Ruby. It - - 1. Simplifies the generation of complex SQL queries - 2. Adapts to various RDBMSes - - It is intended to be a framework framework; that is, you can build your own ORM - with it, focusing on innovative object and collection modeling as opposed to - database compatibility and query generation. -email: -- aaron@tenderlovemaking.com -- bryan@brynary.com -- miloops@gmail.com -executables: [] -extensions: [] -extra_rdoc_files: -- History.txt -- MIT-LICENSE.txt -- README.markdown -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/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/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 -homepage: https://github.com/rails/arel -licenses: -- MIT -metadata: {} -post_install_message: -rdoc_options: -- "--main" -- README.markdown -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: '0' -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: '0' -requirements: [] -rubyforge_project: -rubygems_version: 2.4.7 -signing_key: -specification_version: 4 -summary: Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby -test_files: [] -has_rdoc: diff -Nru ruby-arel-6.0.3/Rakefile ruby-arel-6.0.4/Rakefile --- ruby-arel-6.0.3/Rakefile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/Rakefile 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,24 @@ +require 'bundler' +Bundler::GemHelper.install_tasks + +require 'rake/testtask' + +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 -Nru ruby-arel-6.0.3/test/attributes/test_attribute.rb ruby-arel-6.0.4/test/attributes/test_attribute.rb --- ruby-arel-6.0.3/test/attributes/test_attribute.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/attributes/test_attribute.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,907 @@ +require 'helper' + +module Arel + module Attributes + describe 'attribute' do + describe '#not_eq' do + it 'should create a NotEqual node' do + relation = Table.new(:users) + relation[:id].not_eq(10).must_be_kind_of Nodes::NotEqual + end + + it 'should generate != in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].not_eq(10) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" != 10 + } + end + + it 'should handle nil' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].not_eq(nil) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" IS NOT NULL + } + end + end + + describe '#not_eq_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].not_eq_any([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].not_eq_any([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" != 1 OR "users"."id" != 2) + } + end + end + + describe '#not_eq_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].not_eq_all([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].not_eq_all([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" != 1 AND "users"."id" != 2) + } + end + end + + describe '#gt' do + it 'should create a GreaterThan node' do + relation = Table.new(:users) + relation[:id].gt(10).must_be_kind_of Nodes::GreaterThan + end + + it 'should generate > in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].gt(10) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" > 10 + } + end + + it 'should handle comparing with a subquery' do + users = Table.new(:users) + + avg = users.project(users[:karma].average) + mgr = users.project(Arel.star).where(users[:karma].gt(avg)) + + mgr.to_sql.must_be_like %{ + SELECT * FROM "users" WHERE "users"."karma" > (SELECT AVG("users"."karma") FROM "users") + } + end + + it 'should accept various data types.' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].gt('fake_name') + mgr.to_sql.must_match %{"users"."name" > 'fake_name'} + + current_time = ::Time.now + mgr.where relation[:created_at].gt(current_time) + mgr.to_sql.must_match %{"users"."created_at" > '#{current_time}'} + end + end + + describe '#gt_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].gt_any([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].gt_any([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" > 1 OR "users"."id" > 2) + } + end + end + + describe '#gt_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].gt_all([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].gt_all([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" > 1 AND "users"."id" > 2) + } + end + end + + describe '#gteq' do + it 'should create a GreaterThanOrEqual node' do + relation = Table.new(:users) + relation[:id].gteq(10).must_be_kind_of Nodes::GreaterThanOrEqual + end + + it 'should generate >= in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].gteq(10) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" >= 10 + } + end + + it 'should accept various data types.' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].gteq('fake_name') + mgr.to_sql.must_match %{"users"."name" >= 'fake_name'} + + current_time = ::Time.now + mgr.where relation[:created_at].gteq(current_time) + mgr.to_sql.must_match %{"users"."created_at" >= '#{current_time}'} + end + end + + describe '#gteq_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].gteq_any([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].gteq_any([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" >= 1 OR "users"."id" >= 2) + } + end + end + + describe '#gteq_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].gteq_all([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].gteq_all([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" >= 1 AND "users"."id" >= 2) + } + end + end + + describe '#lt' do + it 'should create a LessThan node' do + relation = Table.new(:users) + relation[:id].lt(10).must_be_kind_of Nodes::LessThan + end + + it 'should generate < in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].lt(10) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" < 10 + } + end + + it 'should accept various data types.' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].lt('fake_name') + mgr.to_sql.must_match %{"users"."name" < 'fake_name'} + + current_time = ::Time.now + mgr.where relation[:created_at].lt(current_time) + mgr.to_sql.must_match %{"users"."created_at" < '#{current_time}'} + end + end + + describe '#lt_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].lt_any([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].lt_any([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" < 1 OR "users"."id" < 2) + } + end + end + + describe '#lt_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].lt_all([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].lt_all([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" < 1 AND "users"."id" < 2) + } + end + end + + describe '#lteq' do + it 'should create a LessThanOrEqual node' do + relation = Table.new(:users) + relation[:id].lteq(10).must_be_kind_of Nodes::LessThanOrEqual + end + + it 'should generate <= in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].lteq(10) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" <= 10 + } + end + + it 'should accept various data types.' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].lteq('fake_name') + mgr.to_sql.must_match %{"users"."name" <= 'fake_name'} + + current_time = ::Time.now + mgr.where relation[:created_at].lteq(current_time) + mgr.to_sql.must_match %{"users"."created_at" <= '#{current_time}'} + end + end + + describe '#lteq_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].lteq_any([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].lteq_any([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" <= 1 OR "users"."id" <= 2) + } + end + end + + describe '#lteq_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].lteq_all([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].lteq_all([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" <= 1 AND "users"."id" <= 2) + } + end + end + + describe '#average' do + it 'should create a AVG node' do + relation = Table.new(:users) + relation[:id].average.must_be_kind_of Nodes::Avg + end + + it 'should generate the proper SQL' do + relation = Table.new(:users) + mgr = relation.project relation[:id].average + mgr.to_sql.must_be_like %{ + SELECT AVG("users"."id") + FROM "users" + } + end + end + + describe '#maximum' do + it 'should create a MAX node' do + relation = Table.new(:users) + relation[:id].maximum.must_be_kind_of Nodes::Max + end + + it 'should generate the proper SQL' do + relation = Table.new(:users) + mgr = relation.project relation[:id].maximum + mgr.to_sql.must_be_like %{ + SELECT MAX("users"."id") + FROM "users" + } + end + end + + describe '#minimum' do + it 'should create a Min node' do + relation = Table.new(:users) + relation[:id].minimum.must_be_kind_of Nodes::Min + end + end + + describe '#sum' do + it 'should create a SUM node' do + relation = Table.new(:users) + relation[:id].sum.must_be_kind_of Nodes::Sum + end + + it 'should generate the proper SQL' do + relation = Table.new(:users) + mgr = relation.project relation[:id].sum + mgr.to_sql.must_be_like %{ + SELECT SUM("users"."id") + FROM "users" + } + end + end + + describe '#count' do + it 'should return a count node' do + relation = Table.new(:users) + relation[:id].count.must_be_kind_of Nodes::Count + end + + it 'should take a distinct param' do + relation = Table.new(:users) + count = relation[:id].count(nil) + count.must_be_kind_of Nodes::Count + count.distinct.must_be_nil + end + end + + describe '#eq' do + it 'should return an equality node' do + attribute = Attribute.new nil, nil + equality = attribute.eq 1 + equality.left.must_equal attribute + equality.right.val.must_equal 1 + equality.must_be_kind_of Nodes::Equality + end + + it 'should generate = in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].eq(10) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" = 10 + } + end + + it 'should handle nil' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].eq(nil) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" IS NULL + } + end + end + + describe '#eq_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].eq_any([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].eq_any([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 OR "users"."id" = 2) + } + end + + it 'should not eat input' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + values = [1,2] + mgr.where relation[:id].eq_any(values) + values.must_equal [1,2] + end + end + + describe '#eq_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].eq_all([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].eq_all([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 AND "users"."id" = 2) + } + end + + it 'should not eat input' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + values = [1,2] + mgr.where relation[:id].eq_all(values) + values.must_equal [1,2] + end + end + + describe '#matches' do + it 'should create a Matches node' do + relation = Table.new(:users) + relation[:name].matches('%bacon%').must_be_kind_of Nodes::Matches + end + + it 'should generate LIKE in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].matches('%bacon%') + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."name" LIKE '%bacon%' + } + end + end + + describe '#matches_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:name].matches_any(['%chunky%','%bacon%']).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].matches_any(['%chunky%','%bacon%']) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."name" LIKE '%chunky%' OR "users"."name" LIKE '%bacon%') + } + end + end + + describe '#matches_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:name].matches_all(['%chunky%','%bacon%']).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].matches_all(['%chunky%','%bacon%']) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."name" LIKE '%chunky%' AND "users"."name" LIKE '%bacon%') + } + end + end + + describe '#does_not_match' do + it 'should create a DoesNotMatch node' do + relation = Table.new(:users) + relation[:name].does_not_match('%bacon%').must_be_kind_of Nodes::DoesNotMatch + end + + it 'should generate NOT LIKE in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].does_not_match('%bacon%') + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."name" NOT LIKE '%bacon%' + } + end + end + + describe '#does_not_match_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:name].does_not_match_any(['%chunky%','%bacon%']).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].does_not_match_any(['%chunky%','%bacon%']) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."name" NOT LIKE '%chunky%' OR "users"."name" NOT LIKE '%bacon%') + } + end + end + + describe '#does_not_match_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:name].does_not_match_all(['%chunky%','%bacon%']).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%']) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."name" NOT LIKE '%chunky%' AND "users"."name" NOT LIKE '%bacon%') + } + 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 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 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 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 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 + 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 'can be constructed with a random object' do + attribute = Attribute.new nil, nil + 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 + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].in([1,2,3]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" IN (1, 2, 3) + } + end + end + + describe '#in_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].in_any([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].in_any([[1,2], [3,4]]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" IN (1, 2) OR "users"."id" IN (3, 4)) + } + end + end + + describe '#in_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].in_all([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].in_all([[1,2], [3,4]]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" IN (1, 2) AND "users"."id" IN (3, 4)) + } + 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 'can be constructed with a random object' do + attribute = Attribute.new nil, nil + 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 + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].not_in([1,2,3]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" NOT IN (1, 2, 3) + } + end + end + + describe '#not_in_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].not_in_any([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].not_in_any([[1,2], [3,4]]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" NOT IN (1, 2) OR "users"."id" NOT IN (3, 4)) + } + end + end + + describe '#not_in_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].not_in_all([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].not_in_all([[1,2], [3,4]]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" NOT IN (1, 2) AND "users"."id" NOT IN (3, 4)) + } + end + end + + describe '#eq_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].eq_all([1,2]).must_be_kind_of Nodes::Grouping + end + + it 'should generate ANDs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].eq_all([1,2]) + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 AND "users"."id" = 2) + } + end + end + + describe '#asc' do + it 'should create an Ascending node' do + relation = Table.new(:users) + relation[:id].asc.must_be_kind_of Nodes::Ascending + end + + it 'should generate ASC in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.order relation[:id].asc + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" ORDER BY "users"."id" ASC + } + end + end + + describe '#desc' do + it 'should create a Descending node' do + relation = Table.new(:users) + relation[:id].desc.must_be_kind_of Nodes::Descending + end + + it 'should generate DESC in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.order relation[:id].desc + mgr.to_sql.must_be_like %{ + SELECT "users"."id" FROM "users" ORDER BY "users"."id" DESC + } + end + end + end + + describe 'equality' do + describe '#to_sql' do + it 'should produce sql' do + table = Table.new :users + condition = table['id'].eq 1 + condition.to_sql.must_equal '"users"."id" = 1' + end + end + end + end +end diff -Nru ruby-arel-6.0.3/test/collectors/test_bind_collector.rb ruby-arel-6.0.4/test/collectors/test_bind_collector.rb --- ruby-arel-6.0.3/test/collectors/test_bind_collector.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/collectors/test_bind_collector.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,70 @@ +require 'helper' +require 'arel/collectors/bind' + +module Arel + module Collectors + class TestBindCollector < Arel::Test + def setup + @conn = FakeRecord::Base.new + @visitor = Visitors::ToSql.new @conn.connection + super + end + + def collect node + @visitor.accept(node, Collectors::Bind.new) + end + + def compile node + collect(node).value + end + + def ast_with_binds bv + table = Table.new(:users) + manager = Arel::SelectManager.new Table.engine, table + manager.where(table[:age].eq(bv)) + manager.where(table[:name].eq(bv)) + manager.ast + end + + def test_leaves_binds + 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 + list = compile ast_with_binds bv + assert_operator list.length, :>, 0 + assert_equal bv, list.grep(Nodes::BindParam).first + assert_equal bv.class, list.grep(Nodes::BindParam).first.class + end + + def test_substitute_binds + bv = Nodes::BindParam.new + collector = collect ast_with_binds bv + + values = collector.value + + offsets = values.map.with_index { |v,i| + [v,i] + }.find_all { |(v,_)| Nodes::BindParam === v }.map(&:last) + + list = collector.substitute_binds ["hello", "world"] + assert_equal "hello", list[offsets[0]] + assert_equal "world", list[offsets[1]] + + assert_equal 'SELECT FROM "users" WHERE "users"."age" = hello AND "users"."name" = world', list.join + end + + def test_compile + bv = Nodes::BindParam.new + collector = collect ast_with_binds bv + + sql = collector.compile ["hello", "world"] + assert_equal 'SELECT FROM "users" WHERE "users"."age" = hello AND "users"."name" = world', sql + end + end + end +end diff -Nru ruby-arel-6.0.3/test/collectors/test_sql_string.rb ruby-arel-6.0.4/test/collectors/test_sql_string.rb --- ruby-arel-6.0.3/test/collectors/test_sql_string.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/collectors/test_sql_string.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,38 @@ +require 'helper' +require 'arel/collectors/bind' + +module Arel + module Collectors + class TestSqlString < Arel::Test + def setup + @conn = FakeRecord::Base.new + @visitor = Visitors::ToSql.new @conn.connection + super + end + + def collect node + @visitor.accept(node, Collectors::SQLString.new) + end + + def compile node + collect(node).value + end + + def ast_with_binds bv + table = Table.new(:users) + manager = Arel::SelectManager.new Table.engine, table + manager.where(table[:age].eq(bv)) + manager.where(table[:name].eq(bv)) + manager.ast + end + + def test_compile + bv = Nodes::BindParam.new + collector = collect ast_with_binds bv + + sql = collector.compile ["hello", "world"] + assert_equal 'SELECT FROM "users" WHERE "users"."age" = ? AND "users"."name" = ?', sql + end + end + end +end diff -Nru ruby-arel-6.0.3/test/helper.rb ruby-arel-6.0.4/test/helper.rb --- ruby-arel-6.0.3/test/helper.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/helper.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,22 @@ +require 'rubygems' +require 'minitest/autorun' +require 'fileutils' +require 'arel' + +require 'support/fake_record' +Arel::Table.engine = FakeRecord::Base.new + +class Object + def must_be_like other + gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip + end +end + +module Arel + class Test < MiniTest::Test + def assert_like expected, actual + assert_equal expected.gsub(/\s+/, ' ').strip, + actual.gsub(/\s+/, ' ').strip + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_and.rb ruby-arel-6.0.4/test/nodes/test_and.rb --- ruby-arel-6.0.3/test/nodes/test_and.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_and.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,20 @@ +require 'helper' + +module Arel + module Nodes + describe 'And' do + describe 'equality' do + it 'is equal with equal ivars' do + array = [And.new(['foo', 'bar']), And.new(['foo', 'bar'])] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [And.new(['foo', 'bar']), And.new(['foo', 'baz'])] + assert_equal 2, array.uniq.size + end + end + end + end +end + diff -Nru ruby-arel-6.0.3/test/nodes/test_ascending.rb ruby-arel-6.0.4/test/nodes/test_ascending.rb --- ruby-arel-6.0.3/test/nodes/test_ascending.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_ascending.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,44 @@ +require 'helper' + +module Arel + module Nodes + class TestAscending < Minitest::Test + def test_construct + ascending = Ascending.new 'zomg' + assert_equal 'zomg', ascending.expr + end + + def test_reverse + ascending = Ascending.new 'zomg' + descending = ascending.reverse + assert_kind_of Descending, descending + assert_equal ascending.expr, descending.expr + end + + def test_direction + ascending = Ascending.new 'zomg' + assert_equal :asc, ascending.direction + end + + def test_ascending? + ascending = Ascending.new 'zomg' + assert ascending.ascending? + end + + def test_descending? + ascending = Ascending.new 'zomg' + assert !ascending.descending? + end + + def test_equality_with_same_ivars + array = [Ascending.new('zomg'), Ascending.new('zomg')] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [Ascending.new('zomg'), Ascending.new('zomg!')] + assert_equal 2, array.uniq.size + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_as.rb ruby-arel-6.0.4/test/nodes/test_as.rb --- ruby-arel-6.0.3/test/nodes/test_as.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_as.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,34 @@ +require 'helper' + +module Arel + module Nodes + describe 'As' do + describe '#as' do + it 'makes an AS node' do + attr = Table.new(:users)[:id] + as = attr.as(Arel.sql('foo')) + assert_equal attr, as.left + assert_equal 'foo', as.right + end + + it 'converts right to SqlLiteral if a string' do + attr = Table.new(:users)[:id] + as = attr.as('foo') + assert_kind_of Arel::Nodes::SqlLiteral, as.right + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [As.new('foo', 'bar'), As.new('foo', 'bar')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [As.new('foo', 'bar'), As.new('foo', 'baz')] + assert_equal 2, array.uniq.size + end + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_binary.rb ruby-arel-6.0.4/test/nodes/test_binary.rb --- ruby-arel-6.0.3/test/nodes/test_binary.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_binary.rb 2016-12-27 13:51:36.000000000 +0000 @@ -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 -Nru ruby-arel-6.0.3/test/nodes/test_bin.rb ruby-arel-6.0.4/test/nodes/test_bin.rb --- ruby-arel-6.0.3/test/nodes/test_bin.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_bin.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,33 @@ +require 'helper' + +module Arel + module Nodes + class TestBin < Minitest::Test + def test_new + assert Arel::Nodes::Bin.new('zomg') + end + + def test_default_to_sql + viz = Arel::Visitors::ToSql.new Table.engine.connection_pool + node = Arel::Nodes::Bin.new(Arel.sql('zomg')) + assert_equal 'zomg', viz.accept(node, Collectors::SQLString.new).value + end + + def test_mysql_to_sql + viz = Arel::Visitors::MySQL.new Table.engine.connection_pool + node = Arel::Nodes::Bin.new(Arel.sql('zomg')) + assert_equal 'BINARY zomg', viz.accept(node, Collectors::SQLString.new).value + end + + def test_equality_with_same_ivars + array = [Bin.new('zomg'), Bin.new('zomg')] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [Bin.new('zomg'), Bin.new('zomg!')] + assert_equal 2, array.uniq.size + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_count.rb ruby-arel-6.0.4/test/nodes/test_count.rb --- ruby-arel-6.0.3/test/nodes/test_count.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_count.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,33 @@ +require 'helper' + +describe Arel::Nodes::Count do + describe "as" do + it 'should alias the count' do + table = Arel::Table.new :users + table[:id].count.as('foo').to_sql.must_be_like %{ + COUNT("users"."id") AS foo + } + end + end + + describe "eq" do + it "should compare the count" do + table = Arel::Table.new :users + table[:id].count.eq(2).to_sql.must_be_like %{ + COUNT("users"."id") = 2 + } + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [Arel::Nodes::Count.new('foo'), Arel::Nodes::Count.new('foo')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Arel::Nodes::Count.new('foo'), Arel::Nodes::Count.new('foo!')] + assert_equal 2, array.uniq.size + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_delete_statement.rb ruby-arel-6.0.4/test/nodes/test_delete_statement.rb --- ruby-arel-6.0.3/test/nodes/test_delete_statement.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_delete_statement.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,34 @@ +require 'helper' + +describe Arel::Nodes::DeleteStatement do + describe "#clone" do + it "clones wheres" do + statement = Arel::Nodes::DeleteStatement.new + statement.wheres = %w[a b c] + + dolly = statement.clone + dolly.wheres.must_equal statement.wheres + dolly.wheres.wont_be_same_as statement.wheres + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + statement1 = Arel::Nodes::DeleteStatement.new + statement1.wheres = %w[a b c] + statement2 = Arel::Nodes::DeleteStatement.new + statement2.wheres = %w[a b c] + array = [statement1, statement2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + statement1 = Arel::Nodes::DeleteStatement.new + statement1.wheres = %w[a b c] + statement2 = Arel::Nodes::DeleteStatement.new + statement2.wheres = %w[1 2 3] + array = [statement1, statement2] + assert_equal 2, array.uniq.size + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_descending.rb ruby-arel-6.0.4/test/nodes/test_descending.rb --- ruby-arel-6.0.3/test/nodes/test_descending.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_descending.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,44 @@ +require 'helper' + +module Arel + module Nodes + class TestDescending < Minitest::Test + def test_construct + descending = Descending.new 'zomg' + assert_equal 'zomg', descending.expr + end + + def test_reverse + descending = Descending.new 'zomg' + ascending = descending.reverse + assert_kind_of Ascending, ascending + assert_equal descending.expr, ascending.expr + end + + def test_direction + descending = Descending.new 'zomg' + assert_equal :desc, descending.direction + end + + def test_ascending? + descending = Descending.new 'zomg' + assert !descending.ascending? + end + + def test_descending? + descending = Descending.new 'zomg' + assert descending.descending? + end + + def test_equality_with_same_ivars + array = [Descending.new('zomg'), Descending.new('zomg')] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [Descending.new('zomg'), Descending.new('zomg!')] + assert_equal 2, array.uniq.size + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_distinct.rb ruby-arel-6.0.4/test/nodes/test_distinct.rb --- ruby-arel-6.0.3/test/nodes/test_distinct.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_distinct.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,20 @@ +require 'helper' + +module Arel + module Nodes + describe 'Distinct' do + describe 'equality' do + it 'is equal to other distinct nodes' do + array = [Distinct.new, Distinct.new] + assert_equal 1, array.uniq.size + end + + it 'is not equal with other nodes' do + array = [Distinct.new, Node.new] + assert_equal 2, array.uniq.size + end + end + end + end +end + diff -Nru ruby-arel-6.0.3/test/nodes/test_equality.rb ruby-arel-6.0.4/test/nodes/test_equality.rb --- ruby-arel-6.0.3/test/nodes/test_equality.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_equality.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,84 @@ +require 'helper' + +module Arel + module Nodes + describe 'equality' do + # FIXME: backwards compat + describe 'backwards compat' do + describe 'operator' do + it 'returns :==' do + attr = Table.new(:users)[:id] + left = attr.eq(10) + left.operator.must_equal :== + end + end + + describe 'operand1' do + it "should equal left" do + attr = Table.new(:users)[:id] + left = attr.eq(10) + left.left.must_equal left.operand1 + end + end + + describe 'operand2' do + it "should equal right" do + attr = Table.new(:users)[:id] + left = attr.eq(10) + left.right.must_equal left.operand2 + end + end + + describe 'to_sql' do + it 'takes an engine' do + engine = FakeRecord::Base.new + engine.connection.extend Module.new { + attr_accessor :quote_count + def quote(*args) @quote_count += 1; super; end + def quote_column_name(*args) @quote_count += 1; super; end + def quote_table_name(*args) @quote_count += 1; super; end + } + engine.connection.quote_count = 0 + + attr = Table.new(:users)[:id] + test = attr.eq(10) + test.to_sql engine + engine.connection.quote_count.must_equal 3 + end + end + end + + describe 'or' do + it 'makes an OR node' do + attr = Table.new(:users)[:id] + left = attr.eq(10) + right = attr.eq(11) + node = left.or right + node.expr.left.must_equal left + node.expr.right.must_equal right + end + end + + describe 'and' do + it 'makes and AND node' do + attr = Table.new(:users)[:id] + left = attr.eq(10) + right = attr.eq(11) + node = left.and right + node.left.must_equal left + node.right.must_equal right + end + end + + it 'is equal with equal ivars' do + array = [Equality.new('foo', 'bar'), Equality.new('foo', 'bar')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Equality.new('foo', 'bar'), Equality.new('foo', 'baz')] + assert_equal 2, array.uniq.size + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_extract.rb ruby-arel-6.0.4/test/nodes/test_extract.rb --- ruby-arel-6.0.3/test/nodes/test_extract.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_extract.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,41 @@ +require 'helper' + +describe Arel::Nodes::Extract do + it "should extract field" do + table = Arel::Table.new :users + table[:timestamp].extract('date').to_sql.must_be_like %{ + EXTRACT(DATE FROM "users"."timestamp") + } + end + + describe "as" do + it 'should alias the extract' do + table = Arel::Table.new :users + table[:timestamp].extract('date').as('foo').to_sql.must_be_like %{ + EXTRACT(DATE FROM "users"."timestamp") AS foo + } + end + + it 'should not mutate the extract' do + table = Arel::Table.new :users + extract = table[:timestamp].extract('date') + before = extract.dup + extract.as('foo') + assert_equal extract, before + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + table = Arel::Table.new :users + array = [table[:attr].extract('foo'), table[:attr].extract('foo')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + table = Arel::Table.new :users + array = [table[:attr].extract('foo'), table[:attr].extract('bar')] + assert_equal 2, array.uniq.size + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_false.rb ruby-arel-6.0.4/test/nodes/test_false.rb --- ruby-arel-6.0.3/test/nodes/test_false.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_false.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,20 @@ +require 'helper' + +module Arel + module Nodes + describe 'False' do + describe 'equality' do + it 'is equal to other false nodes' do + array = [False.new, False.new] + assert_equal 1, array.uniq.size + end + + it 'is not equal with other nodes' do + array = [False.new, Node.new] + assert_equal 2, array.uniq.size + end + end + end + end +end + diff -Nru ruby-arel-6.0.3/test/nodes/test_grouping.rb ruby-arel-6.0.4/test/nodes/test_grouping.rb --- ruby-arel-6.0.3/test/nodes/test_grouping.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_grouping.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,25 @@ +require 'helper' + +module Arel + module Nodes + describe 'Grouping' do + it 'should create Equality nodes' do + grouping = Grouping.new(Nodes.build_quoted('foo')) + grouping.eq('foo').to_sql.must_be_like %q{('foo') = 'foo'} + end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [Grouping.new('foo'), Grouping.new('foo')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Grouping.new('foo'), Grouping.new('bar')] + assert_equal 2, array.uniq.size + end + end + end + end +end + diff -Nru ruby-arel-6.0.3/test/nodes/test_infix_operation.rb ruby-arel-6.0.4/test/nodes/test_infix_operation.rb --- ruby-arel-6.0.3/test/nodes/test_infix_operation.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_infix_operation.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,40 @@ +require 'helper' + +module Arel + module Nodes + class TestInfixOperation < Minitest::Test + def test_construct + operation = InfixOperation.new :+, 1, 2 + assert_equal :+, operation.operator + assert_equal 1, operation.left + assert_equal 2, operation.right + end + + def test_operation_alias + operation = InfixOperation.new :+, 1, 2 + aliaz = operation.as('zomg') + assert_kind_of As, aliaz + assert_equal operation, aliaz.left + assert_equal 'zomg', aliaz.right + end + + def test_operation_ordering + operation = InfixOperation.new :+, 1, 2 + ordering = operation.desc + assert_kind_of Descending, ordering + assert_equal operation, ordering.expr + assert ordering.descending? + end + + def test_equality_with_same_ivars + array = [InfixOperation.new(:+, 1, 2), InfixOperation.new(:+, 1, 2)] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [InfixOperation.new(:+, 1, 2), InfixOperation.new(:+, 1, 3)] + assert_equal 2, array.uniq.size + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_insert_statement.rb ruby-arel-6.0.4/test/nodes/test_insert_statement.rb --- ruby-arel-6.0.3/test/nodes/test_insert_statement.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_insert_statement.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,42 @@ +require 'helper' + +describe Arel::Nodes::InsertStatement do + describe "#clone" do + it "clones columns and values" do + statement = Arel::Nodes::InsertStatement.new + statement.columns = %w[a b c] + statement.values = %w[x y z] + + dolly = statement.clone + dolly.columns.must_equal statement.columns + dolly.values.must_equal statement.values + + dolly.columns.wont_be_same_as statement.columns + dolly.values.wont_be_same_as statement.values + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + statement1 = Arel::Nodes::InsertStatement.new + statement1.columns = %w[a b c] + statement1.values = %w[x y z] + statement2 = Arel::Nodes::InsertStatement.new + statement2.columns = %w[a b c] + statement2.values = %w[x y z] + array = [statement1, statement2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + statement1 = Arel::Nodes::InsertStatement.new + statement1.columns = %w[a b c] + statement1.values = %w[x y z] + statement2 = Arel::Nodes::InsertStatement.new + statement2.columns = %w[a b c] + statement2.values = %w[1 2 3] + array = [statement1, statement2] + assert_equal 2, array.uniq.size + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_named_function.rb ruby-arel-6.0.4/test/nodes/test_named_function.rb --- ruby-arel-6.0.3/test/nodes/test_named_function.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_named_function.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,46 @@ +require 'helper' + +module Arel + module Nodes + class TestNamedFunction < Minitest::Test + def test_construct + function = NamedFunction.new 'omg', 'zomg' + assert_equal 'omg', function.name + assert_equal 'zomg', function.expressions + end + + def test_function_alias + function = NamedFunction.new 'omg', 'zomg' + function = function.as('wth') + assert_equal 'omg', function.name + assert_equal 'zomg', function.expressions + assert_kind_of SqlLiteral, function.alias + assert_equal 'wth', function.alias + end + + def test_construct_with_alias + function = NamedFunction.new 'omg', 'zomg', 'wth' + assert_equal 'omg', function.name + assert_equal 'zomg', function.expressions + assert_kind_of SqlLiteral, function.alias + assert_equal 'wth', function.alias + end + + def test_equality_with_same_ivars + array = [ + NamedFunction.new('omg', 'zomg', 'wth'), + NamedFunction.new('omg', 'zomg', 'wth') + ] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [ + NamedFunction.new('omg', 'zomg', 'wth'), + NamedFunction.new('zomg', 'zomg', 'wth') + ] + assert_equal 2, array.uniq.size + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_node.rb ruby-arel-6.0.4/test/nodes/test_node.rb --- ruby-arel-6.0.3/test/nodes/test_node.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_node.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,39 @@ +require 'helper' + +module Arel + class TestNode < Minitest::Test + def test_includes_factory_methods + assert Node.new.respond_to?(:create_join) + end + + def test_all_nodes_are_nodes + Nodes.constants.map { |k| + Nodes.const_get(k) + }.grep(Class).each do |klass| + next if Nodes::SqlLiteral == klass + next if Nodes::BindParam == klass + next if klass.name =~ /^Arel::Nodes::Test/ + assert klass.ancestors.include?(Nodes::Node), klass.name + end + end + + def test_each + list = [] + node = Nodes::Node.new + node.each { |n| list << n } + assert_equal [node], list + end + + def test_generator + list = [] + node = Nodes::Node.new + node.each.each { |n| list << n } + assert_equal [node], list + end + + def test_enumerable + node = Nodes::Node.new + assert_kind_of Enumerable, node + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_not.rb ruby-arel-6.0.4/test/nodes/test_not.rb --- ruby-arel-6.0.3/test/nodes/test_not.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_not.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,29 @@ +require 'helper' + +module Arel + module Nodes + describe 'not' do + describe '#not' do + it 'makes a NOT node' do + attr = Table.new(:users)[:id] + expr = attr.eq(10) + node = expr.not + node.must_be_kind_of Not + node.expr.must_equal expr + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [Not.new('foo'), Not.new('foo')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Not.new('foo'), Not.new('baz')] + assert_equal 2, array.uniq.size + end + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_or.rb ruby-arel-6.0.4/test/nodes/test_or.rb --- ruby-arel-6.0.3/test/nodes/test_or.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_or.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,34 @@ +require 'helper' + +module Arel + module Nodes + describe 'or' do + describe '#or' do + it 'makes an OR node' do + attr = Table.new(:users)[:id] + left = attr.eq(10) + right = attr.eq(11) + node = left.or right + node.expr.left.must_equal left + node.expr.right.must_equal right + + oror = node.or(right) + oror.expr.left.must_equal node + oror.expr.right.must_equal right + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [Or.new('foo', 'bar'), Or.new('foo', 'bar')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Or.new('foo', 'bar'), Or.new('foo', 'baz')] + assert_equal 2, array.uniq.size + end + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_over.rb ruby-arel-6.0.4/test/nodes/test_over.rb --- ruby-arel-6.0.3/test/nodes/test_over.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_over.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,67 @@ +require 'helper' + +describe Arel::Nodes::Over do + describe 'as' do + it 'should alias the expression' do + table = Arel::Table.new :users + table[:id].count.over.as('foo').to_sql.must_be_like %{ + COUNT("users"."id") OVER () AS foo + } + end + end + + describe 'with literal' do + it 'should reference the window definition by name' do + table = Arel::Table.new :users + table[:id].count.over('foo').to_sql.must_be_like %{ + COUNT("users"."id") OVER "foo" + } + end + end + + describe 'with SQL literal' do + it 'should reference the window definition by name' do + table = Arel::Table.new :users + table[:id].count.over(Arel.sql('foo')).to_sql.must_be_like %{ + COUNT("users"."id") OVER foo + } + end + end + + describe 'with no expression' do + it 'should use empty definition' do + table = Arel::Table.new :users + table[:id].count.over.to_sql.must_be_like %{ + COUNT("users"."id") OVER () + } + end + end + + describe 'with expression' do + it 'should use definition in sub-expression' do + table = Arel::Table.new :users + window = Arel::Nodes::Window.new.order(table['foo']) + table[:id].count.over(window).to_sql.must_be_like %{ + COUNT("users"."id") OVER (ORDER BY \"users\".\"foo\") + } + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [ + Arel::Nodes::Over.new('foo', 'bar'), + Arel::Nodes::Over.new('foo', 'bar') + ] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [ + Arel::Nodes::Over.new('foo', 'bar'), + Arel::Nodes::Over.new('foo', 'baz') + ] + assert_equal 2, array.uniq.size + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_select_core.rb ruby-arel-6.0.4/test/nodes/test_select_core.rb --- ruby-arel-6.0.3/test/nodes/test_select_core.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_select_core.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,69 @@ +require 'helper' + +module Arel + module Nodes + class TestSelectCore < Minitest::Test + def test_clone + core = Arel::Nodes::SelectCore.new + core.froms = %w[a b c] + core.projections = %w[d e f] + core.wheres = %w[g h i] + + dolly = core.clone + + assert_equal core.froms, dolly.froms + assert_equal core.projections, dolly.projections + assert_equal core.wheres, dolly.wheres + + refute_same core.froms, dolly.froms + refute_same core.projections, dolly.projections + refute_same core.wheres, dolly.wheres + end + + def test_set_quantifier + core = Arel::Nodes::SelectCore.new + core.set_quantifier = Arel::Nodes::Distinct.new + viz = Arel::Visitors::ToSql.new Table.engine.connection_pool + assert_match 'DISTINCT', viz.accept(core, Collectors::SQLString.new).value + end + + def test_equality_with_same_ivars + core1 = SelectCore.new + core1.froms = %w[a b c] + core1.projections = %w[d e f] + core1.wheres = %w[g h i] + core1.groups = %w[j k l] + core1.windows = %w[m n o] + core1.having = %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] + array = [core1, core2] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + core1 = SelectCore.new + core1.froms = %w[a b c] + core1.projections = %w[d e f] + core1.wheres = %w[g h i] + core1.groups = %w[j k l] + core1.windows = %w[m n o] + core1.having = %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] + array = [core1, core2] + assert_equal 2, array.uniq.size + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_select_statement.rb ruby-arel-6.0.4/test/nodes/test_select_statement.rb --- ruby-arel-6.0.3/test/nodes/test_select_statement.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_select_statement.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,49 @@ +require 'helper' + +describe Arel::Nodes::SelectStatement do + describe "#clone" do + it "clones cores" do + statement = Arel::Nodes::SelectStatement.new %w[a b c] + + dolly = statement.clone + dolly.cores.must_equal statement.cores + dolly.cores.wont_be_same_as statement.cores + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + statement1 = Arel::Nodes::SelectStatement.new %w[a b c] + statement1.offset = 1 + statement1.limit = 2 + statement1.lock = false + statement1.orders = %w[x y z] + statement1.with = 'zomg' + statement2 = Arel::Nodes::SelectStatement.new %w[a b c] + statement2.offset = 1 + statement2.limit = 2 + statement2.lock = false + statement2.orders = %w[x y z] + statement2.with = 'zomg' + array = [statement1, statement2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + statement1 = Arel::Nodes::SelectStatement.new %w[a b c] + statement1.offset = 1 + statement1.limit = 2 + statement1.lock = false + statement1.orders = %w[x y z] + statement1.with = 'zomg' + statement2 = Arel::Nodes::SelectStatement.new %w[a b c] + statement2.offset = 1 + statement2.limit = 2 + statement2.lock = false + statement2.orders = %w[x y z] + statement2.with = 'wth' + array = [statement1, statement2] + assert_equal 2, array.uniq.size + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_sql_literal.rb ruby-arel-6.0.4/test/nodes/test_sql_literal.rb --- ruby-arel-6.0.3/test/nodes/test_sql_literal.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_sql_literal.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,73 @@ +require 'helper' +require 'yaml' + +module Arel + module Nodes + describe 'sql literal' do + before do + @visitor = Visitors::ToSql.new Table.engine.connection + end + + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + + describe 'sql' do + it 'makes a sql literal node' do + sql = Arel.sql 'foo' + sql.must_be_kind_of Arel::Nodes::SqlLiteral + end + end + + describe 'count' do + it 'makes a count node' do + node = SqlLiteral.new('*').count + compile(node).must_be_like %{ COUNT(*) } + end + + it 'makes a distinct node' do + node = SqlLiteral.new('*').count true + compile(node).must_be_like %{ COUNT(DISTINCT *) } + end + end + + describe 'equality' do + it 'makes an equality node' do + node = SqlLiteral.new('foo').eq(1) + compile(node).must_be_like %{ foo = 1 } + end + + it 'is equal with equal contents' do + array = [SqlLiteral.new('foo'), SqlLiteral.new('foo')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different contents' do + array = [SqlLiteral.new('foo'), SqlLiteral.new('bar')] + assert_equal 2, array.uniq.size + end + end + + describe 'grouped "or" equality' do + it 'makes a grouping node with an or node' do + node = SqlLiteral.new('foo').eq_any([1,2]) + compile(node).must_be_like %{ (foo = 1 OR foo = 2) } + end + end + + describe 'grouped "and" equality' do + it 'makes a grouping node with an or node' do + node = SqlLiteral.new('foo').eq_all([1,2]) + compile(node).must_be_like %{ (foo = 1 AND foo = 2) } + end + end + + describe 'serialization' do + it 'serializes into YAML' do + yaml_literal = SqlLiteral.new('foo').to_yaml + assert_equal('foo', YAML.load(yaml_literal)) + end + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_sum.rb ruby-arel-6.0.4/test/nodes/test_sum.rb --- ruby-arel-6.0.3/test/nodes/test_sum.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_sum.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,33 @@ +require 'helper' + +describe Arel::Nodes::Sum do + describe "as" do + it 'should alias the sum' do + table = Arel::Table.new :users + table[:id].sum.as('foo').to_sql.must_be_like %{ + SUM("users"."id") AS foo + } + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [Arel::Nodes::Sum.new('foo'), Arel::Nodes::Sum.new('foo')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Arel::Nodes::Sum.new('foo'), Arel::Nodes::Sum.new('foo!')] + 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 -Nru ruby-arel-6.0.3/test/nodes/test_table_alias.rb ruby-arel-6.0.4/test/nodes/test_table_alias.rb --- ruby-arel-6.0.3/test/nodes/test_table_alias.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_table_alias.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,36 @@ +require 'helper' +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') + node1 = TableAlias.new relation1, :foo + relation2 = Table.new(:users, 'vroom') + 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') + node1 = TableAlias.new relation1, :foo + relation2 = Table.new(:users, 'vroom') + node2 = TableAlias.new relation2, :bar + array = [node1, node2] + assert_equal 2, array.uniq.size + end + end + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_true.rb ruby-arel-6.0.4/test/nodes/test_true.rb --- ruby-arel-6.0.3/test/nodes/test_true.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_true.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,21 @@ +require 'helper' + +module Arel + module Nodes + describe 'True' do + describe 'equality' do + it 'is equal to other true nodes' do + array = [True.new, True.new] + assert_equal 1, array.uniq.size + end + + it 'is not equal with other nodes' do + array = [True.new, Node.new] + assert_equal 2, array.uniq.size + end + end + end + end +end + + diff -Nru ruby-arel-6.0.3/test/nodes/test_update_statement.rb ruby-arel-6.0.4/test/nodes/test_update_statement.rb --- ruby-arel-6.0.3/test/nodes/test_update_statement.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_update_statement.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,58 @@ +require 'helper' + +describe Arel::Nodes::UpdateStatement do + describe "#clone" do + it "clones wheres and values" do + statement = Arel::Nodes::UpdateStatement.new + statement.wheres = %w[a b c] + statement.values = %w[x y z] + + dolly = statement.clone + dolly.wheres.must_equal statement.wheres + dolly.wheres.wont_be_same_as statement.wheres + + dolly.values.must_equal statement.values + dolly.values.wont_be_same_as statement.values + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + statement1 = Arel::Nodes::UpdateStatement.new + statement1.relation = 'zomg' + statement1.wheres = 2 + statement1.values = false + statement1.orders = %w[x y z] + statement1.limit = 42 + statement1.key = 'zomg' + statement2 = Arel::Nodes::UpdateStatement.new + statement2.relation = 'zomg' + statement2.wheres = 2 + statement2.values = false + statement2.orders = %w[x y z] + statement2.limit = 42 + statement2.key = 'zomg' + array = [statement1, statement2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + statement1 = Arel::Nodes::UpdateStatement.new + statement1.relation = 'zomg' + statement1.wheres = 2 + statement1.values = false + statement1.orders = %w[x y z] + statement1.limit = 42 + statement1.key = 'zomg' + statement2 = Arel::Nodes::UpdateStatement.new + statement2.relation = 'zomg' + statement2.wheres = 2 + statement2.values = false + statement2.orders = %w[x y z] + statement2.limit = 42 + statement2.key = 'wth' + array = [statement1, statement2] + assert_equal 2, array.uniq.size + end + end +end diff -Nru ruby-arel-6.0.3/test/nodes/test_window.rb ruby-arel-6.0.4/test/nodes/test_window.rb --- ruby-arel-6.0.3/test/nodes/test_window.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/nodes/test_window.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,79 @@ +require 'helper' + +module Arel + module Nodes + describe 'Window' do + describe 'equality' do + it 'is equal with equal ivars' do + window1 = Window.new + window1.orders = [1, 2] + window1.partitions = [1] + window1.frame 3 + window2 = Window.new + window2.orders = [1, 2] + window2.partitions = [1] + window2.frame 3 + array = [window1, window2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + window1 = Window.new + window1.orders = [1, 2] + window1.partitions = [1] + window1.frame 3 + window2 = Window.new + window2.orders = [1, 2] + window1.partitions = [1] + window2.frame 4 + array = [window1, window2] + assert_equal 2, array.uniq.size + end + end + end + + describe 'NamedWindow' do + describe 'equality' do + it 'is equal with equal ivars' do + window1 = NamedWindow.new 'foo' + window1.orders = [1, 2] + window1.partitions = [1] + window1.frame 3 + window2 = NamedWindow.new 'foo' + window2.orders = [1, 2] + window2.partitions = [1] + window2.frame 3 + array = [window1, window2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + window1 = NamedWindow.new 'foo' + window1.orders = [1, 2] + window1.partitions = [1] + window1.frame 3 + window2 = NamedWindow.new 'bar' + window2.orders = [1, 2] + window2.partitions = [1] + window2.frame 3 + array = [window1, window2] + assert_equal 2, array.uniq.size + end + end + end + + describe 'CurrentRow' do + describe 'equality' do + it 'is equal to other current row nodes' do + array = [CurrentRow.new, CurrentRow.new] + assert_equal 1, array.uniq.size + end + + it 'is not equal with other nodes' do + array = [CurrentRow.new, Node.new] + assert_equal 2, array.uniq.size + end + end + end + end +end \ No newline at end of file diff -Nru ruby-arel-6.0.3/test/support/fake_record.rb ruby-arel-6.0.4/test/support/fake_record.rb --- ruby-arel-6.0.3/test/support/fake_record.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/support/fake_record.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,135 @@ +module FakeRecord + class Column < Struct.new(:name, :type) + end + + class Connection + attr_reader :tables + attr_accessor :visitor + + def initialize(visitor = nil) + @tables = %w{ users photos developers products} + @columns = { + 'users' => [ + Column.new('id', :integer), + Column.new('name', :string), + Column.new('bool', :boolean), + Column.new('created_at', :date) + ], + 'products' => [ + Column.new('id', :integer), + Column.new('price', :decimal) + ] + } + @columns_hash = { + 'users' => Hash[@columns['users'].map { |x| [x.name, x] }], + 'products' => Hash[@columns['products'].map { |x| [x.name, x] }] + } + @primary_keys = { + 'users' => 'id', + 'products' => 'id' + } + @visitor = visitor + end + + def columns_hash table_name + @columns_hash[table_name] + end + + def primary_key name + @primary_keys[name.to_s] + end + + def table_exists? name + @tables.include? name.to_s + end + + def columns name, message = nil + @columns[name.to_s] + end + + def quote_table_name name + "\"#{name.to_s}\"" + end + + def quote_column_name name + "\"#{name.to_s}\"" + end + + def schema_cache + self + end + + def quote thing, column = nil + if column && !thing.nil? + case column.type + when :integer + thing = thing.to_i + when :string + thing = thing.to_s + end + end + + case thing + when DateTime + "'#{thing.strftime("%Y-%m-%d %H:%M:%S")}'" + when Date + "'#{thing.strftime("%Y-%m-%d")}'" + when true + "'t'" + when false + "'f'" + when nil + 'NULL' + when Numeric + thing + else + "'#{thing.to_s.gsub("'", "\\\\'")}'" + end + end + end + + class ConnectionPool + class Spec < Struct.new(:config) + end + + attr_reader :spec, :connection + + def initialize + @spec = Spec.new(:adapter => 'america') + @connection = Connection.new + @connection.visitor = Arel::Visitors::ToSql.new(connection) + end + + def with_connection + yield connection + end + + def table_exists? name + connection.tables.include? name.to_s + end + + def columns_hash + connection.columns_hash + end + + def schema_cache + connection + end + + def quote thing, column = nil + connection.quote thing, column + end + end + + class Base + attr_accessor :connection_pool + + def initialize + @connection_pool = ConnectionPool.new + end + + def connection + connection_pool.connection + end + end +end diff -Nru ruby-arel-6.0.3/test/test_attributes.rb ruby-arel-6.0.4/test/test_attributes.rb --- ruby-arel-6.0.3/test/test_attributes.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/test_attributes.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,66 @@ +require 'helper' + +module Arel + describe 'Attributes' do + it 'responds to lower' do + relation = Table.new(:users) + attribute = relation[:foo] + node = attribute.lower + assert_equal 'LOWER', node.name + assert_equal [attribute], node.expressions + end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [Attribute.new('foo', 'bar'), Attribute.new('foo', 'bar')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Attribute.new('foo', 'bar'), Attribute.new('foo', 'baz')] + assert_equal 2, array.uniq.size + end + end + + describe 'for' do + it 'deals with unknown column types' do + column = Struct.new(:type).new :crazy + Attributes.for(column).must_equal Attributes::Undefined + end + + it 'returns the correct constant for strings' do + [:string, :text, :binary].each do |type| + column = Struct.new(:type).new type + Attributes.for(column).must_equal Attributes::String + end + end + + it 'returns the correct constant for ints' do + column = Struct.new(:type).new :integer + Attributes.for(column).must_equal Attributes::Integer + end + + it 'returns the correct constant for floats' do + column = Struct.new(:type).new :float + Attributes.for(column).must_equal Attributes::Float + end + + it 'returns the correct constant for decimals' do + column = Struct.new(:type).new :decimal + Attributes.for(column).must_equal Attributes::Decimal + end + + it 'returns the correct constant for boolean' do + column = Struct.new(:type).new :boolean + Attributes.for(column).must_equal Attributes::Boolean + end + + it 'returns the correct constant for time' do + [:date, :datetime, :timestamp, :time].each do |type| + column = Struct.new(:type).new type + Attributes.for(column).must_equal Attributes::Time + end + end + end + end +end diff -Nru ruby-arel-6.0.3/test/test_crud.rb ruby-arel-6.0.4/test/test_crud.rb --- ruby-arel-6.0.3/test/test_crud.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/test_crud.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,63 @@ +require 'helper' + +module Arel + class FakeCrudder < SelectManager + class FakeEngine + attr_reader :calls, :connection_pool, :spec, :config + + def initialize + @calls = [] + @connection_pool = self + @spec = self + @config = { :adapter => 'sqlite3' } + end + + def connection; self end + + def method_missing name, *args + @calls << [name, args] + end + end + + include Crud + + attr_reader :engine + attr_accessor :ctx + + def initialize engine = FakeEngine.new + super + end + end + + describe 'crud' do + describe 'insert' do + it 'should call insert on the connection' do + table = Table.new :users + fc = FakeCrudder.new + fc.from table + im = fc.compile_insert [[table[:id], 'foo']] + assert_instance_of Arel::InsertManager, im + end + end + + describe 'update' do + it 'should call update on the connection' do + table = Table.new :users + fc = FakeCrudder.new + fc.from table + stmt = fc.compile_update [[table[:id], 'foo']], Arel::Attributes::Attribute.new(table, 'id') + assert_instance_of Arel::UpdateManager, stmt + end + end + + describe 'delete' do + it 'should call delete on the connection' do + table = Table.new :users + fc = FakeCrudder.new + fc.from table + stmt = fc.compile_delete + assert_instance_of Arel::DeleteManager, stmt + end + end + end +end diff -Nru ruby-arel-6.0.3/test/test_delete_manager.rb ruby-arel-6.0.4/test/test_delete_manager.rb --- ruby-arel-6.0.3/test/test_delete_manager.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/test_delete_manager.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,42 @@ +require 'helper' + +module Arel + describe 'delete manager' do + describe 'new' do + it 'takes an engine' do + Arel::DeleteManager.new Table.engine + end + end + + describe 'from' do + it 'uses from' do + table = Table.new(:users) + dm = Arel::DeleteManager.new Table.engine + 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.from(table).must_equal dm + end + end + + describe 'where' do + it 'uses where values' do + table = Table.new(:users) + dm = Arel::DeleteManager.new Table.engine + dm.from table + dm.where table[:id].eq(10) + dm.to_sql.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10} + end + + it 'chains' do + table = Table.new(:users) + dm = Arel::DeleteManager.new Table.engine + dm.where(table[:id].eq(10)).must_equal dm + end + end + end +end diff -Nru ruby-arel-6.0.3/test/test_factory_methods.rb ruby-arel-6.0.4/test/test_factory_methods.rb --- ruby-arel-6.0.3/test/test_factory_methods.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/test_factory_methods.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,44 @@ +require 'helper' + +module Arel + module FactoryMethods + class TestFactoryMethods < Minitest::Test + class Factory + include Arel::FactoryMethods + end + + def setup + @factory = Factory.new + end + + def test_create_join + join = @factory.create_join :one, :two + assert_kind_of Nodes::Join, join + assert_equal :two, join.right + end + + def test_create_on + on = @factory.create_on :one + assert_instance_of Nodes::On, on + assert_equal :one, on.expr + end + + def test_create_true + true_node = @factory.create_true + assert_instance_of Nodes::True, true_node + end + + def test_create_false + false_node = @factory.create_false + assert_instance_of Nodes::False, false_node + end + + def test_lower + lower = @factory.lower :one + assert_instance_of Nodes::NamedFunction, lower + assert_equal 'LOWER', lower.name + assert_equal [:one], lower.expressions.map(&:expr) + end + end + end +end diff -Nru ruby-arel-6.0.3/test/test_insert_manager.rb ruby-arel-6.0.4/test/test_insert_manager.rb --- ruby-arel-6.0.3/test/test_insert_manager.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/test_insert_manager.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,171 @@ +require 'helper' + +module Arel + describe 'insert manager' do + describe 'new' do + it 'takes an engine' do + Arel::InsertManager.new Table.engine + end + end + + describe 'insert' do + it 'can create a Values node' do + manager = Arel::InsertManager.new Table.engine + values = manager.create_values %w{ a b }, %w{ c d } + + assert_kind_of Arel::Nodes::Values, values + assert_equal %w{ a b }, values.left + assert_equal %w{ c d }, values.right + end + + it 'allows sql literals' do + manager = Arel::InsertManager.new Table.engine + manager.into Table.new(:users) + manager.values = manager.create_values [Arel.sql('*')], %w{ a } + manager.to_sql.must_be_like %{ + INSERT INTO \"users\" VALUES (*) + } + end + + it "inserts false" do + table = Table.new(:users) + manager = Arel::InsertManager.new Table.engine + + manager.insert [[table[:bool], false]] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("bool") VALUES ('f') + } + end + + it "inserts null" do + table = Table.new(:users) + manager = Arel::InsertManager.new Table.engine + manager.insert [[table[:id], nil]] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("id") VALUES (NULL) + } + end + + it "inserts time" do + table = Table.new(:users) + manager = Arel::InsertManager.new Table.engine + + time = Time.now + attribute = table[:created_at] + + manager.insert [[attribute, time]] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("created_at") VALUES (#{Table.engine.connection.quote time}) + } + end + + it 'takes a list of lists' do + table = Table.new(:users) + manager = Arel::InsertManager.new Table.engine + manager.into table + manager.insert [[table[:id], 1], [table[:name], 'aaron']] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') + } + end + + it 'defaults the table' do + table = Table.new(:users) + manager = Arel::InsertManager.new Table.engine + manager.insert [[table[:id], 1], [table[:name], 'aaron']] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') + } + end + + it 'noop for empty list' do + table = Table.new(:users) + manager = Arel::InsertManager.new Table.engine + manager.insert [[table[:id], 1]] + manager.insert [] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("id") VALUES (1) + } + end + end + + describe 'into' do + it 'takes a Table and chains' do + manager = Arel::InsertManager.new Table.engine + 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.into table + manager.to_sql.must_be_like %{ + INSERT INTO "users" + } + end + end + + describe 'columns' do + it "converts to sql" do + table = Table.new :users + manager = Arel::InsertManager.new Table.engine + manager.into table + manager.columns << table[:id] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("id") + } + end + end + + describe "values" do + it "converts to sql" do + table = Table.new :users + manager = Arel::InsertManager.new Table.engine + manager.into table + + manager.values = Nodes::Values.new [1] + manager.to_sql.must_be_like %{ + INSERT INTO "users" VALUES (1) + } + end + end + + describe "combo" do + it "combines columns and values list in order" do + table = Table.new :users + manager = Arel::InsertManager.new Table.engine + manager.into table + + manager.values = Nodes::Values.new [1, 'aaron'] + manager.columns << table[:id] + manager.columns << table[:name] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') + } + end + end + + describe "select" do + + it "accepts a select query in place of a VALUES clause" do + table = Table.new :users + + manager = Arel::InsertManager.new Table.engine + manager.into table + + select = Arel::SelectManager.new Table.engine + select.project Arel.sql('1') + select.project Arel.sql('"aaron"') + + manager.select select + manager.columns << table[:id] + manager.columns << table[:name] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("id", "name") (SELECT 1, "aaron") + } + end + + end + + end +end diff -Nru ruby-arel-6.0.3/test/test_select_manager.rb ruby-arel-6.0.4/test/test_select_manager.rb --- ruby-arel-6.0.3/test/test_select_manager.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/test_select_manager.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,1211 @@ +require 'helper' + +module Arel + + describe 'select manager' do + def test_join_sources + manager = Arel::SelectManager.new Table.engine + 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 + assert_equal [], manager.bind_values + manager.bind_values = [1] + assert_equal [1], manager.bind_values + end + + describe 'backwards compatibility' do + describe 'project' do + it 'accepts symbols as sql literals' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.project :id + manager.from table + manager.to_sql.must_be_like %{ + SELECT id FROM "users" + } + end + end + + describe 'order' do + it 'accepts symbols' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.project Nodes::SqlLiteral.new '*' + manager.from table + manager.order :foo + manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo } + end + end + + describe 'group' do + it 'takes a symbol' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.group :foo + manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo } + end + end + + describe 'as' do + it 'makes an AS node by grouping the AST' do + manager = Arel::SelectManager.new Table.engine + as = manager.as(Arel.sql('foo')) + assert_kind_of Arel::Nodes::Grouping, as.left + assert_equal manager.ast, as.left.expr + assert_equal 'foo', as.right + end + + it 'converts right to SqlLiteral if a string' do + manager = Arel::SelectManager.new Table.engine + 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.project Arel.star + manager.from Arel.sql('zomg') + as = manager.as(Arel.sql('foo')) + + manager = Arel::SelectManager.new Table.engine + manager.project Arel.sql('name') + manager.from as + manager.to_sql.must_be_like "SELECT name FROM (SELECT * FROM zomg) foo" + end + end + + describe 'from' do + it 'ignores strings when table of same name exists' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + + manager.from table + manager.from 'users' + manager.project table['id'] + manager.to_sql.must_be_like 'SELECT "users"."id" FROM users' + end + + it 'should support any ast' do + table = Table.new :users + manager1 = Arel::SelectManager.new Table.engine + + manager2 = Arel::SelectManager.new Table.engine + manager2.project(Arel.sql('*')) + manager2.from table + + manager1.project Arel.sql('lol') + as = manager2.as Arel.sql('omg') + manager1.from(as) + + manager1.to_sql.must_be_like %{ + SELECT lol FROM (SELECT * FROM "users") omg + } + end + end + + describe 'having' do + it 'converts strings to SQLLiterals' do + table = Table.new :users + mgr = table.from table + mgr.having '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.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar } + end + + it 'can have multiple items specified together' do + table = Table.new :users + mgr = table.from table + mgr.having 'foo', 'bar' + mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar } + end + end + + describe 'on' do + it 'converts to sqlliterals' do + table = Table.new :users + right = table.alias + mgr = table.from table + mgr.join(right).on("omg") + mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg } + end + + it 'converts to sqlliterals with multiple items' do + table = Table.new :users + right = table.alias + mgr = table.from table + 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 + end + end + + describe 'clone' do + it 'creates new cores' do + table = Table.new :users, :as => 'foo' + mgr = table.from table + m2 = mgr.clone + m2.project "foo" + mgr.to_sql.wont_equal m2.to_sql + end + + it 'makes updates to the correct copy' do + table = Table.new :users, :as => 'foo' + mgr = table.from table + m2 = mgr.clone + m3 = m2.clone + m2.project "foo" + mgr.to_sql.wont_equal m2.to_sql + m3.to_sql.must_equal mgr.to_sql + end + end + + describe 'initialize' do + it 'uses alias in sql' do + table = Table.new :users, :as => 'foo' + mgr = table.from table + mgr.skip 10 + mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 } + end + end + + describe 'skip' do + it 'should add an offset' do + table = Table.new :users + mgr = table.from table + 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.skip(10).to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } + end + end + + describe 'offset' do + it 'should add an offset' do + table = Table.new :users + mgr = table.from table + 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.offset = 10 + mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } + + mgr.offset = nil + mgr.to_sql.must_be_like %{ SELECT FROM "users" } + end + + it 'should return the offset' do + table = Table.new :users + mgr = table.from table + mgr.offset = 10 + assert_equal 10, mgr.offset + end + end + + describe 'exists' do + it 'should create an exists clause' do + table = Table.new(:users) + manager = Arel::SelectManager.new Table.engine, table + manager.project Nodes::SqlLiteral.new '*' + m2 = Arel::SelectManager.new(manager.engine) + m2.project manager.exists + m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) } + end + + it 'can be aliased' do + table = Table.new(:users) + manager = Arel::SelectManager.new Table.engine, table + manager.project Nodes::SqlLiteral.new '*' + m2 = Arel::SelectManager.new(manager.engine) + m2.project manager.exists.as('foo') + m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) AS foo } + end + end + + describe 'union' do + before do + table = Table.new :users + @m1 = Arel::SelectManager.new Table.engine, table + @m1.project Arel.star + @m1.where(table[:age].lt(18)) + + @m2 = Arel::SelectManager.new Table.engine, table + @m2.project Arel.star + @m2.where(table[:age].gt(99)) + + + end + + it 'should union two managers' do + # FIXME should this union "managers" or "statements" ? + # FIXME this probably shouldn't return a node + node = @m1.union @m2 + + # maybe FIXME: decide when wrapper parens are needed + node.to_sql.must_be_like %{ + ( SELECT * FROM "users" WHERE "users"."age" < 18 UNION SELECT * FROM "users" WHERE "users"."age" > 99 ) + } + end + + it 'should union all' do + node = @m1.union :all, @m2 + + node.to_sql.must_be_like %{ + ( SELECT * FROM "users" WHERE "users"."age" < 18 UNION ALL SELECT * FROM "users" WHERE "users"."age" > 99 ) + } + end + + end + + describe 'intersect' do + before do + table = Table.new :users + @m1 = Arel::SelectManager.new Table.engine, table + @m1.project Arel.star + @m1.where(table[:age].gt(18)) + + @m2 = Arel::SelectManager.new Table.engine, table + @m2.project Arel.star + @m2.where(table[:age].lt(99)) + + + end + + it 'should interect two managers' do + # FIXME should this intersect "managers" or "statements" ? + # FIXME this probably shouldn't return a node + node = @m1.intersect @m2 + + # maybe FIXME: decide when wrapper parens are needed + node.to_sql.must_be_like %{ + ( SELECT * FROM "users" WHERE "users"."age" > 18 INTERSECT SELECT * FROM "users" WHERE "users"."age" < 99 ) + } + end + + end + + describe 'except' do + before do + table = Table.new :users + @m1 = Arel::SelectManager.new Table.engine, table + @m1.project Arel.star + @m1.where(table[:age].between(18..60)) + + @m2 = Arel::SelectManager.new Table.engine, table + @m2.project Arel.star + @m2.where(table[:age].between(40..99)) + end + + it 'should except two managers' do + # FIXME should this except "managers" or "statements" ? + # FIXME this probably shouldn't return a node + node = @m1.except @m2 + + # maybe FIXME: decide when wrapper parens are needed + node.to_sql.must_be_like %{ + ( SELECT * FROM "users" WHERE "users"."age" BETWEEN 18 AND 60 EXCEPT SELECT * FROM "users" WHERE "users"."age" BETWEEN 40 AND 99 ) + } + end + + end + + describe 'with' do + it 'should support basic WITH' do + users = Table.new(:users) + users_top = Table.new(:users_top) + comments = Table.new(:comments) + + top = users.project(users[:id]).where(users[:karma].gt(100)) + users_as = Arel::Nodes::As.new(users_top, top) + select_manager = comments.project(Arel.star).with(users_as) + .where(comments[:author_id].in(users_top.project(users_top[:id]))) + + select_manager.to_sql.must_be_like %{ + WITH "users_top" AS (SELECT "users"."id" FROM "users" WHERE "users"."karma" > 100) SELECT * FROM "comments" WHERE "comments"."author_id" IN (SELECT "users_top"."id" FROM "users_top") + } + end + + it "should support WITH RECURSIVE" do + comments = Table.new(:comments) + comments_id = comments[:id] + comments_parent_id = comments[:parent_id] + + replies = Table.new(:replies) + replies_id = replies[:id] + + recursive_term = Arel::SelectManager.new Table.engine + 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.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.with(:recursive, as_statement).from(replies).project(Arel.star) + + sql = manager.to_sql + sql.must_be_like %{ + WITH RECURSIVE "replies" AS ( + SELECT "comments"."id", "comments"."parent_id" FROM "comments" WHERE "comments"."id" = 42 + UNION + SELECT "comments"."id", "comments"."parent_id" FROM "comments" INNER JOIN "replies" ON "comments"."parent_id" = "replies"."id" + ) + SELECT * FROM "replies" + } + end + end + + describe 'ast' do + it 'should return the ast' do + table = Table.new :users + mgr = table.from table + 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.project Arel.sql '*' + mgr.from table + mgr.orders << Arel::Nodes::Ascending.new(Arel.sql('foo')) + mgr.ast.grep(Arel::Nodes::OuterJoin) + mgr.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo ASC } + end + end + + describe 'taken' do + it 'should return limit' do + manager = Arel::SelectManager.new Table.engine + manager.take 10 + manager.taken.must_equal 10 + end + end + + describe 'lock' do + # This should fail on other databases + it 'adds a lock node' do + table = Table.new :users + mgr = table.from table + mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" FOR UPDATE } + end + end + + describe 'orders' do + it 'returns order clauses' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + order = table[:id] + manager.order table[:id] + manager.orders.must_equal [order] + end + end + + describe 'order' do + it 'generates order clauses' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.project Nodes::SqlLiteral.new '*' + manager.from table + manager.order table[:id] + manager.to_sql.must_be_like %{ + SELECT * FROM "users" ORDER BY "users"."id" + } + end + + # FIXME: I would like to deprecate this + it 'takes *args' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.project Nodes::SqlLiteral.new '*' + manager.from table + manager.order table[:id], table[:name] + manager.to_sql.must_be_like %{ + SELECT * FROM "users" ORDER BY "users"."id", "users"."name" + } + end + + it 'chains' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.order(table[:id]).must_equal manager + end + + it 'has order attributes' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.project Nodes::SqlLiteral.new '*' + manager.from table + manager.order table[:id].desc + manager.to_sql.must_be_like %{ + SELECT * FROM "users" ORDER BY "users"."id" DESC + } + end + end + + describe 'on' do + it 'takes two params' do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + manager = Arel::SelectManager.new Table.engine + + manager.from left + manager.join(right).on(predicate, predicate) + manager.to_sql.must_be_like %{ + SELECT FROM "users" + INNER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" AND + "users"."id" = "users_2"."id" + } + end + + it 'takes three params' do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + manager = Arel::SelectManager.new Table.engine + + manager.from left + manager.join(right).on( + predicate, + predicate, + left[:name].eq(right[:name]) + ) + manager.to_sql.must_be_like %{ + SELECT FROM "users" + INNER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" AND + "users"."id" = "users_2"."id" AND + "users"."name" = "users_2"."name" + } + end + end + + it 'should hand back froms' do + relation = Arel::SelectManager.new Table.engine + assert_equal [], relation.froms + end + + it 'should create and nodes' do + relation = Arel::SelectManager.new Table.engine + children = ['foo', 'bar', 'baz'] + clause = relation.create_and children + assert_kind_of Arel::Nodes::And, clause + assert_equal children, clause.children + end + + it 'should create insert managers' do + relation = Arel::SelectManager.new Table.engine + insert = relation.create_insert + assert_kind_of Arel::InsertManager, insert + end + + it 'should create join nodes' do + relation = Arel::SelectManager.new Table.engine + join = relation.create_join 'foo', 'bar' + assert_kind_of Arel::Nodes::InnerJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + + it 'should create join nodes with a full outer join klass' do + relation = Arel::SelectManager.new Table.engine + join = relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin + assert_kind_of Arel::Nodes::FullOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + + it 'should create join nodes with a outer join klass' do + relation = Arel::SelectManager.new Table.engine + join = relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin + assert_kind_of Arel::Nodes::OuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + + it 'should create join nodes with a right outer join klass' do + relation = Arel::SelectManager.new Table.engine + join = relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin + assert_kind_of Arel::Nodes::RightOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + + describe 'join' do + it 'responds to join' do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + manager = Arel::SelectManager.new Table.engine + + manager.from left + manager.join(right).on(predicate) + manager.to_sql.must_be_like %{ + SELECT FROM "users" + INNER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + + it 'takes a class' do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + manager = Arel::SelectManager.new Table.engine + + manager.from left + manager.join(right, Nodes::OuterJoin).on(predicate) + manager.to_sql.must_be_like %{ + SELECT FROM "users" + LEFT OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + 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 Table.engine + + 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 Table.engine + + 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.join(nil).must_equal manager + end + end + + describe 'outer join' do + it 'responds to join' do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + manager = Arel::SelectManager.new Table.engine + + manager.from left + manager.outer_join(right).on(predicate) + manager.to_sql.must_be_like %{ + SELECT FROM "users" + LEFT OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + + it 'noops on nil' do + manager = Arel::SelectManager.new Table.engine + manager.outer_join(nil).must_equal manager + end + end + + describe 'joins' do + + it 'returns inner join sql' do + table = Table.new :users + aliaz = table.alias + manager = Arel::SelectManager.new Table.engine + 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 + end + + it 'returns outer join sql' do + table = Table.new :users + aliaz = table.alias + manager = Arel::SelectManager.new Table.engine + 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 + end + + it 'can have a non-table alias as relation name' do + users = Table.new :users + comments = Table.new :comments + + counts = comments.from(comments). + group(comments[:user_id]). + project( + comments[:user_id].as("user_id"), + comments[:user_id].count.as("count") + ).as("counts") + + joins = users.join(counts).on(counts[:user_id].eq(10)) + joins.to_sql.must_be_like %{ + SELECT FROM "users" INNER JOIN (SELECT "comments"."user_id" AS user_id, COUNT("comments"."user_id") AS count FROM "comments" GROUP BY "comments"."user_id") counts ON counts."user_id" = 10 + } + end + + it "joins itself" do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + + mgr = left.join(right) + mgr.project Nodes::SqlLiteral.new('*') + mgr.on(predicate).must_equal mgr + + mgr.to_sql.must_be_like %{ + SELECT * FROM "users" + INNER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + + it 'returns string join sql' do + manager = Arel::SelectManager.new Table.engine + manager.from Nodes::StringJoin.new(Nodes.build_quoted('hello')) + assert_match "'hello'", manager.to_sql + end + end + + describe 'group' do + it 'takes an attribute' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.group table[:id] + manager.to_sql.must_be_like %{ + SELECT FROM "users" GROUP BY "users"."id" + } + end + + it 'chains' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.group(table[:id]).must_equal manager + end + + it 'takes multiple args' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.group table[:id], table[:name] + manager.to_sql.must_be_like %{ + SELECT FROM "users" GROUP BY "users"."id", "users"."name" + } + end + + # FIXME: backwards compat + it 'makes strings literals' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.group 'foo' + manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo } + end + end + + describe 'window definition' do + it 'can be empty' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window') + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS () + } + end + + it 'takes an order' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').order(table['foo'].asc) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (ORDER BY "users"."foo" ASC) + } + end + + it 'takes an order with multiple columns' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').order(table['foo'].asc, table['bar'].desc) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (ORDER BY "users"."foo" ASC, "users"."bar" DESC) + } + end + + it 'takes a partition' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').partition(table['bar']) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (PARTITION BY "users"."bar") + } + end + + it 'takes a partition and an order' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').partition(table['foo']).order(table['foo'].asc) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (PARTITION BY "users"."foo" + ORDER BY "users"."foo" ASC) + } + end + + it 'takes a partition with multiple columns' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').partition(table['bar'], table['baz']) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (PARTITION BY "users"."bar", "users"."baz") + } + end + + it 'takes a rows frame, unbounded preceding' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').rows(Arel::Nodes::Preceding.new) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (ROWS UNBOUNDED PRECEDING) + } + end + + it 'takes a rows frame, bounded preceding' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').rows(Arel::Nodes::Preceding.new(5)) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (ROWS 5 PRECEDING) + } + end + + it 'takes a rows frame, unbounded following' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').rows(Arel::Nodes::Following.new) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (ROWS UNBOUNDED FOLLOWING) + } + end + + it 'takes a rows frame, bounded following' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').rows(Arel::Nodes::Following.new(5)) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (ROWS 5 FOLLOWING) + } + end + + it 'takes a rows frame, current row' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').rows(Arel::Nodes::CurrentRow.new) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (ROWS CURRENT ROW) + } + end + + it 'takes a rows frame, between two delimiters' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + window = manager.window('a_window') + window.frame( + Arel::Nodes::Between.new( + window.rows, + Nodes::And.new([ + Arel::Nodes::Preceding.new, + Arel::Nodes::CurrentRow.new + ]))) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) + } + end + + it 'takes a range frame, unbounded preceding' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').range(Arel::Nodes::Preceding.new) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (RANGE UNBOUNDED PRECEDING) + } + end + + it 'takes a range frame, bounded preceding' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').range(Arel::Nodes::Preceding.new(5)) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (RANGE 5 PRECEDING) + } + end + + it 'takes a range frame, unbounded following' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').range(Arel::Nodes::Following.new) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (RANGE UNBOUNDED FOLLOWING) + } + end + + it 'takes a range frame, bounded following' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').range(Arel::Nodes::Following.new(5)) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (RANGE 5 FOLLOWING) + } + end + + it 'takes a range frame, current row' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').range(Arel::Nodes::CurrentRow.new) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (RANGE CURRENT ROW) + } + end + + it 'takes a range frame, between two delimiters' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + window = manager.window('a_window') + window.frame( + Arel::Nodes::Between.new( + window.range, + Nodes::And.new([ + Arel::Nodes::Preceding.new, + Arel::Nodes::CurrentRow.new + ]))) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) + } + end + end + + describe 'delete' do + it "copies from" do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + stmt = manager.compile_delete + + stmt.to_sql.must_be_like %{ DELETE FROM "users" } + end + + it "copies where" do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.where table[:id].eq 10 + stmt = manager.compile_delete + + stmt.to_sql.must_be_like %{ + DELETE FROM "users" WHERE "users"."id" = 10 + } + end + end + + describe 'where_sql' do + it 'gives me back the where sql' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.where table[:id].eq 10 + manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 } + end + + it 'returns nil when there are no wheres' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.where_sql.must_be_nil + end + end + + describe 'update' do + + it 'creates an update statement' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) + + stmt.to_sql.must_be_like %{ + UPDATE "users" SET "id" = 1 + } + end + + it 'takes a string' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) + + stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } + end + + it 'copies limits' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.take 1 + stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) + stmt.key = table['id'] + + stmt.to_sql.must_be_like %{ + UPDATE "users" SET foo = bar + WHERE "users"."id" IN (SELECT "users"."id" FROM "users" LIMIT 1) + } + end + + it 'copies order' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.order :foo + stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) + stmt.key = table['id'] + + stmt.to_sql.must_be_like %{ + UPDATE "users" SET foo = bar + WHERE "users"."id" IN (SELECT "users"."id" FROM "users" ORDER BY foo) + } + end + + it 'copies where clauses' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.where table[:id].eq 10 + manager.from table + stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) + + stmt.to_sql.must_be_like %{ + UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10 + } + end + + it 'copies where clauses when nesting is triggered' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.where table[:foo].eq 10 + manager.take 42 + manager.from table + stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) + + stmt.to_sql.must_be_like %{ + UPDATE "users" SET "id" = 1 WHERE "users"."id" IN (SELECT "users"."id" FROM "users" WHERE "users"."foo" = 10 LIMIT 42) + } + end + + end + + describe 'project' do + it "takes sql literals" do + manager = Arel::SelectManager.new Table.engine + 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.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.project '*' + manager.to_sql.must_be_like %{ SELECT * } + end + + end + + describe 'projections' do + it 'reads projections' do + manager = Arel::SelectManager.new Table.engine + manager.project Arel.sql('foo'), Arel.sql('bar') + manager.projections.must_equal [Arel.sql('foo'), Arel.sql('bar')] + end + end + + describe 'projections=' do + it 'overwrites projections' do + manager = Arel::SelectManager.new Table.engine + manager.project Arel.sql('foo') + manager.projections = [Arel.sql('bar')] + manager.to_sql.must_be_like %{ SELECT bar } + end + end + + describe 'take' do + it "knows take" do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from(table).project(table['id']) + manager.where(table['id'].eq(1)) + manager.take 1 + + manager.to_sql.must_be_like %{ + SELECT "users"."id" + FROM "users" + WHERE "users"."id" = 1 + LIMIT 1 + } + end + + it "chains" do + manager = Arel::SelectManager.new Table.engine + manager.take(1).must_equal manager + end + + it 'removes LIMIT when nil is passed' do + manager = Arel::SelectManager.new Table.engine + manager.limit = 10 + assert_match('LIMIT', manager.to_sql) + + manager.limit = nil + refute_match('LIMIT', manager.to_sql) + end + end + + describe 'where' do + it "knows where" do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from(table).project(table['id']) + manager.where(table['id'].eq(1)) + manager.to_sql.must_be_like %{ + SELECT "users"."id" + FROM "users" + WHERE "users"."id" = 1 + } + end + + it "chains" do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from(table) + manager.project(table['id']).where(table['id'].eq 1).must_equal manager + end + end + + describe 'from' do + it "makes sql" do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + + manager.from table + manager.project table['id'] + manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"' + end + + it "chains" do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from(table).project(table['id']).must_equal manager + manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"' + end + end + + describe 'source' do + it 'returns the join source of the select core' do + manager = Arel::SelectManager.new Table.engine + 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.distinct + manager.ast.cores.last.set_quantifier.class.must_equal Arel::Nodes::Distinct + + manager.distinct(false) + manager.ast.cores.last.set_quantifier.must_equal nil + end + + it "chains" do + manager = Arel::SelectManager.new Table.engine + manager.distinct.must_equal manager + manager.distinct(false).must_equal manager + end + end + + describe 'distinct_on' do + it 'sets the quantifier' do + manager = Arel::SelectManager.new Table.engine + table = Table.new :users + + manager.distinct_on(table['id']) + manager.ast.cores.last.set_quantifier.must_equal Arel::Nodes::DistinctOn.new(table['id']) + + manager.distinct_on(false) + manager.ast.cores.last.set_quantifier.must_equal nil + end + + it "chains" do + manager = Arel::SelectManager.new Table.engine + table = Table.new :users + + manager.distinct_on(table['id']).must_equal manager + manager.distinct_on(false).must_equal manager + end + end + end +end diff -Nru ruby-arel-6.0.3/test/test_table.rb ruby-arel-6.0.4/test/test_table.rb --- ruby-arel-6.0.3/test/test_table.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/test_table.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,253 @@ +require 'helper' + +module Arel + describe Table do + before do + @relation = Table.new(:users) + end + + it 'should create join nodes' do + join = @relation.create_string_join 'foo' + assert_kind_of Arel::Nodes::StringJoin, join + assert_equal 'foo', join.left + end + + it 'should create join nodes' do + join = @relation.create_join 'foo', 'bar' + assert_kind_of Arel::Nodes::InnerJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + + it 'should create join nodes with a klass' do + join = @relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin + assert_kind_of Arel::Nodes::FullOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + + it 'should create join nodes with a klass' do + join = @relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin + assert_kind_of Arel::Nodes::OuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + + it 'should create join nodes with a klass' do + join = @relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin + assert_kind_of Arel::Nodes::RightOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + + it 'should return an insert manager' do + im = @relation.compile_insert 'VALUES(NULL)' + assert_kind_of Arel::InsertManager, im + im.into Table.new(:users) + 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 + sm.to_sql.must_be_like "SELECT FROM \"users\" OFFSET 2" + 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) + mgr.to_sql.must_be_like %{ + SELECT FROM "users" HAVING "users"."id" = 10 + } + end + end + + describe 'backwards compat' do + describe 'join' do + it 'noops on nil' do + mgr = @relation.join nil + + mgr.to_sql.must_be_like %{ SELECT FROM "users" } + end + + it 'takes a second argument for join type' do + right = @relation.alias + predicate = @relation[:id].eq(right[:id]) + mgr = @relation.join(right, Nodes::OuterJoin).on(predicate) + + mgr.to_sql.must_be_like %{ + SELECT FROM "users" + LEFT OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + end + + describe 'join' do + it 'creates an outer join' do + right = @relation.alias + predicate = @relation[:id].eq(right[:id]) + mgr = @relation.outer_join(right).on(predicate) + + mgr.to_sql.must_be_like %{ + SELECT FROM "users" + LEFT OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + end + end + + describe 'group' do + it 'should create a group' do + manager = @relation.group @relation[:id] + manager.to_sql.must_be_like %{ + SELECT FROM "users" GROUP BY "users"."id" + } + end + end + + describe 'alias' do + it 'should create a node that proxies to a table' do + @relation.aliases.must_equal [] + + node = @relation.alias + @relation.aliases.must_equal [node] + node.name.must_equal 'users_2' + node[:id].relation.must_equal node + end + 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' + end + + it 'ignores as if it equals name' do + rel = Table.new :users, :as => 'users' + rel.table_alias.must_be_nil + end + end + + describe 'order' do + it "should take an order" do + manager = @relation.order "foo" + manager.to_sql.must_be_like %{ SELECT FROM "users" ORDER BY foo } + end + end + + describe 'take' do + it "should add a limit" do + manager = @relation.take 1 + manager.project Nodes::SqlLiteral.new '*' + manager.to_sql.must_be_like %{ SELECT * FROM "users" LIMIT 1 } + end + end + + describe 'project' do + it 'can project' do + manager = @relation.project Nodes::SqlLiteral.new '*' + manager.to_sql.must_be_like %{ SELECT * FROM "users" } + end + + it 'takes multiple parameters' do + manager = @relation.project Nodes::SqlLiteral.new('*'), Nodes::SqlLiteral.new('*') + manager.to_sql.must_be_like %{ SELECT *, * FROM "users" } + end + end + + describe 'where' do + it "returns a tree manager" do + manager = @relation.where @relation[:id].eq 1 + manager.project @relation[:id] + manager.must_be_kind_of TreeManager + manager.to_sql.must_be_like %{ + SELECT "users"."id" + FROM "users" + WHERE "users"."id" = 1 + } + end + end + + it "should have a name" do + @relation.name.must_equal 'users' + end + + it "should have a table name" do + @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 + column = @relation[:id] + column.name.must_equal :id + end + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + relation1 = Table.new(:users, 'vroom') + relation1.aliases = %w[a b c] + relation1.table_alias = 'zomg' + relation2 = Table.new(:users, 'vroom') + relation2.aliases = %w[a b c] + relation2.table_alias = 'zomg' + array = [relation1, relation2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + relation1 = Table.new(:users, 'vroom') + relation1.aliases = %w[a b c] + relation1.table_alias = 'zomg' + relation2 = Table.new(:users, 'vroom') + relation2.aliases = %w[x y z] + relation2.table_alias = 'zomg' + array = [relation1, relation2] + assert_equal 2, array.uniq.size + end + end + end +end diff -Nru ruby-arel-6.0.3/test/test_update_manager.rb ruby-arel-6.0.4/test/test_update_manager.rb --- ruby-arel-6.0.3/test/test_update_manager.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/test_update_manager.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,124 @@ +require 'helper' + +module Arel + describe 'update manager' do + describe 'new' do + it 'takes an engine' do + Arel::UpdateManager.new Table.engine + end + end + + it "should not quote sql literals" do + table = Table.new(:users) + um = Arel::UpdateManager.new Table.engine + um.table table + 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.key = 'id' + um.take 10 + um.table table + um.set [[table[:name], nil]] + assert_match(/LIMIT 10/, um.to_sql) + end + + describe 'set' do + it "updates with null" do + table = Table.new(:users) + um = Arel::UpdateManager.new Table.engine + um.table table + um.set [[table[:name], nil]] + um.to_sql.must_be_like %{ UPDATE "users" SET "name" = NULL } + end + + it 'takes a string' do + table = Table.new(:users) + um = Arel::UpdateManager.new Table.engine + um.table table + um.set Nodes::SqlLiteral.new "foo = bar" + um.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } + end + + it 'takes a list of lists' do + table = Table.new(:users) + um = Arel::UpdateManager.new Table.engine + um.table table + um.set [[table[:id], 1], [table[:name], 'hello']] + um.to_sql.must_be_like %{ + UPDATE "users" SET "id" = 1, "name" = 'hello' + } + end + + it 'chains' do + table = Table.new(:users) + um = Arel::UpdateManager.new Table.engine + 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.table Table.new(:users) + um.to_sql.must_be_like %{ UPDATE "users" } + end + + it 'chains' do + um = Arel::UpdateManager.new Table.engine + um.table(Table.new(:users)).must_equal um + end + + it 'generates an update statement with joins' do + um = Arel::UpdateManager.new Table.engine + + table = Table.new(:users) + join_source = Arel::Nodes::JoinSource.new( + table, + [table.create_join(Table.new(:posts))] + ) + + um.table join_source + um.to_sql.must_be_like %{ UPDATE "users" INNER JOIN "posts" } + end + end + + describe 'where' do + it 'generates a where clause' do + table = Table.new :users + um = Arel::UpdateManager.new Table.engine + um.table table + um.where table[:id].eq(1) + um.to_sql.must_be_like %{ + UPDATE "users" WHERE "users"."id" = 1 + } + end + + it 'chains' do + table = Table.new :users + um = Arel::UpdateManager.new Table.engine + um.table table + um.where(table[:id].eq(1)).must_equal um + end + end + + describe 'key' do + before do + @table = Table.new :users + @um = Arel::UpdateManager.new Table.engine + @um.key = @table[:foo] + end + + it 'can be set' do + @um.ast.key.must_equal @table[:foo] + end + + it 'can be accessed' do + @um.key.must_equal @table[:foo] + end + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_bind_visitor.rb ruby-arel-6.0.4/test/visitors/test_bind_visitor.rb --- ruby-arel-6.0.3/test/visitors/test_bind_visitor.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_bind_visitor.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,60 @@ +require 'helper' +require 'arel/visitors/bind_visitor' +require 'support/fake_record' + +module Arel + module Visitors + class TestBindVisitor < Arel::Test + attr_reader :collector + + def setup + @collector = Collectors::SQLString.new + super + end + + ## + # Tests visit_Arel_Nodes_Assignment correctly + # 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.set [[table[:name], bp]] + visitor = Class.new(Arel::Visitors::ToSql) { + include Arel::Visitors::BindVisitor + }.new Table.engine.connection + + assignment = um.ast.values[0] + actual = visitor.accept(assignment, collector) { + "replace" + } + assert actual + value = actual.value + assert_like "\"name\" = replace", value + end + + def test_visitor_yields_on_binds + visitor = Class.new(Arel::Visitors::ToSql) { + include Arel::Visitors::BindVisitor + }.new nil + + bp = Nodes::BindParam.new + called = false + visitor.accept(bp, collector) { called = true } + assert called + end + + def test_visitor_only_yields_on_binds + visitor = Class.new(Arel::Visitors::ToSql) { + include Arel::Visitors::BindVisitor + }.new(nil) + + bp = Arel.sql 'omg' + called = false + + visitor.accept(bp, collector) { called = true } + refute called + end + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_depth_first.rb ruby-arel-6.0.4/test/visitors/test_depth_first.rb --- ruby-arel-6.0.3/test/visitors/test_depth_first.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_depth_first.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,258 @@ +require 'helper' +require 'set' + +module Arel + module Visitors + class TestDepthFirst < Minitest::Test + Collector = Struct.new(:calls) do + def call object + calls << object + end + end + + def setup + @collector = Collector.new [] + @visitor = Visitors::DepthFirst.new @collector + end + + def test_raises_with_object + assert_raises(TypeError) do + @visitor.accept(Object.new) + end + end + + + # unary ops + [ + Arel::Nodes::Not, + Arel::Nodes::Group, + Arel::Nodes::On, + Arel::Nodes::Grouping, + Arel::Nodes::Offset, + Arel::Nodes::Ordering, + Arel::Nodes::Having, + Arel::Nodes::StringJoin, + Arel::Nodes::UnqualifiedColumn, + Arel::Nodes::Top, + Arel::Nodes::Limit, + ].each do |klass| + define_method("test_#{klass.name.gsub('::', '_')}") do + op = klass.new(:a) + @visitor.accept op + assert_equal [:a, op], @collector.calls + end + end + + # functions + [ + Arel::Nodes::Exists, + Arel::Nodes::Avg, + Arel::Nodes::Min, + Arel::Nodes::Max, + Arel::Nodes::Sum, + ].each do |klass| + define_method("test_#{klass.name.gsub('::', '_')}") do + func = klass.new(:a, "b") + @visitor.accept func + assert_equal [:a, "b", false, func], @collector.calls + end + end + + def test_named_function + func = Arel::Nodes::NamedFunction.new(:a, :b, "c") + @visitor.accept func + assert_equal [:a, :b, false, "c", func], @collector.calls + end + + def test_lock + lock = Nodes::Lock.new true + @visitor.accept lock + assert_equal [lock], @collector.calls + end + + def test_count + count = Nodes::Count.new :a, :b, "c" + @visitor.accept count + assert_equal [:a, "c", :b, count], @collector.calls + end + + def test_inner_join + join = Nodes::InnerJoin.new :a, :b + @visitor.accept join + assert_equal [:a, :b, join], @collector.calls + end + + def test_full_outer_join + join = Nodes::FullOuterJoin.new :a, :b + @visitor.accept join + assert_equal [:a, :b, join], @collector.calls + end + + def test_outer_join + join = Nodes::OuterJoin.new :a, :b + @visitor.accept join + assert_equal [:a, :b, join], @collector.calls + end + + def test_right_outer_join + join = Nodes::RightOuterJoin.new :a, :b + @visitor.accept join + assert_equal [:a, :b, join], @collector.calls + end + + [ + Arel::Nodes::Assignment, + Arel::Nodes::Between, + Arel::Nodes::DoesNotMatch, + Arel::Nodes::Equality, + Arel::Nodes::GreaterThan, + Arel::Nodes::GreaterThanOrEqual, + Arel::Nodes::In, + Arel::Nodes::LessThan, + Arel::Nodes::LessThanOrEqual, + Arel::Nodes::Matches, + Arel::Nodes::NotEqual, + Arel::Nodes::NotIn, + Arel::Nodes::Or, + Arel::Nodes::TableAlias, + Arel::Nodes::Values, + Arel::Nodes::As, + Arel::Nodes::DeleteStatement, + Arel::Nodes::JoinSource, + ].each do |klass| + define_method("test_#{klass.name.gsub('::', '_')}") do + binary = klass.new(:a, :b) + @visitor.accept binary + assert_equal [:a, :b, binary], @collector.calls + end + end + + def test_Arel_Nodes_InfixOperation + binary = Arel::Nodes::InfixOperation.new(:o, :a, :b) + @visitor.accept binary + assert_equal [:a, :b, binary], @collector.calls + end + + # N-ary + [ + Arel::Nodes::And, + ].each do |klass| + define_method("test_#{klass.name.gsub('::', '_')}") do + binary = klass.new([:a, :b, :c]) + @visitor.accept binary + assert_equal [:a, :b, :c, binary], @collector.calls + end + end + + [ + Arel::Attributes::Integer, + Arel::Attributes::Float, + Arel::Attributes::String, + Arel::Attributes::Time, + Arel::Attributes::Boolean, + Arel::Attributes::Attribute + ].each do |klass| + define_method("test_#{klass.name.gsub('::', '_')}") do + binary = klass.new(:a, :b) + @visitor.accept binary + assert_equal [:a, :b, binary], @collector.calls + end + end + + def test_table + relation = Arel::Table.new(:users) + @visitor.accept relation + assert_equal ['users', relation], @collector.calls + end + + def test_array + node = Nodes::Or.new(:a, :b) + list = [node] + @visitor.accept list + assert_equal [:a, :b, node, list], @collector.calls + end + + def test_set + node = Nodes::Or.new(:a, :b) + set = Set.new([node]) + @visitor.accept set + assert_equal [:a, :b, node, set], @collector.calls + end + + def test_hash + node = Nodes::Or.new(:a, :b) + hash = { node => node } + @visitor.accept hash + assert_equal [:a, :b, node, :a, :b, node, hash], @collector.calls + end + + def test_update_statement + stmt = Nodes::UpdateStatement.new + stmt.relation = :a + stmt.values << :b + stmt.wheres << :c + stmt.orders << :d + stmt.limit = :e + + @visitor.accept stmt + assert_equal [:a, :b, stmt.values, :c, stmt.wheres, :d, stmt.orders, + :e, stmt], @collector.calls + end + + def test_select_core + core = Nodes::SelectCore.new + core.projections << :a + core.froms = :b + core.wheres << :c + core.groups << :d + core.windows << :e + core.having = :f + + @visitor.accept core + assert_equal [ + :a, core.projections, + :b, [], + core.source, + :c, core.wheres, + :d, core.groups, + :e, core.windows, + :f, + core], @collector.calls + end + + def test_select_statement + ss = Nodes::SelectStatement.new + ss.cores.replace [:a] + ss.orders << :b + ss.limit = :c + ss.lock = :d + ss.offset = :e + + @visitor.accept ss + assert_equal [ + :a, ss.cores, + :b, ss.orders, + :c, + :d, + :e, + ss], @collector.calls + end + + def test_insert_statement + stmt = Nodes::InsertStatement.new + stmt.relation = :a + stmt.columns << :b + stmt.values = :c + + @visitor.accept stmt + assert_equal [:a, :b, stmt.columns, :c, stmt], @collector.calls + end + + def test_node + node = Nodes::Node.new + @visitor.accept node + assert_equal [node], @collector.calls + end + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_dispatch_contamination.rb ruby-arel-6.0.4/test/visitors/test_dispatch_contamination.rb --- ruby-arel-6.0.3/test/visitors/test_dispatch_contamination.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_dispatch_contamination.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,22 @@ +require 'helper' + +module Arel + module Visitors + describe 'avoiding contamination between visitor dispatch tables' do + before do + @connection = Table.engine.connection + @table = Table.new(:users) + end + + it 'dispatches properly after failing upwards' do + node = Nodes::Union.new(Nodes::True.new, Nodes::False.new) + assert_equal "( TRUE UNION FALSE )", node.to_sql + + node.first # from Nodes::Node's Enumerable mixin + + assert_equal "( TRUE UNION FALSE )", node.to_sql + end + end + end +end + diff -Nru ruby-arel-6.0.3/test/visitors/test_dot.rb ruby-arel-6.0.4/test/visitors/test_dot.rb --- ruby-arel-6.0.3/test/visitors/test_dot.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_dot.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,76 @@ +require 'helper' + +module Arel + module Visitors + class TestDot < Minitest::Test + def setup + @visitor = Visitors::Dot.new + end + + # functions + [ + Nodes::Sum, + Nodes::Exists, + Nodes::Max, + Nodes::Min, + Nodes::Avg, + ].each do |klass| + define_method("test_#{klass.name.gsub('::', '_')}") do + op = klass.new(:a, "z") + @visitor.accept op, Collectors::PlainString.new + end + end + + def test_named_function + func = Nodes::NamedFunction.new 'omg', 'omg' + @visitor.accept func, Collectors::PlainString.new + end + + # unary ops + [ + Arel::Nodes::Not, + Arel::Nodes::Group, + Arel::Nodes::On, + Arel::Nodes::Grouping, + Arel::Nodes::Offset, + Arel::Nodes::Ordering, + Arel::Nodes::Having, + Arel::Nodes::UnqualifiedColumn, + Arel::Nodes::Top, + Arel::Nodes::Limit, + ].each do |klass| + define_method("test_#{klass.name.gsub('::', '_')}") do + op = klass.new(:a) + @visitor.accept op, Collectors::PlainString.new + end + end + + # binary ops + [ + Arel::Nodes::Assignment, + Arel::Nodes::Between, + Arel::Nodes::DoesNotMatch, + Arel::Nodes::Equality, + Arel::Nodes::GreaterThan, + Arel::Nodes::GreaterThanOrEqual, + Arel::Nodes::In, + Arel::Nodes::LessThan, + Arel::Nodes::LessThanOrEqual, + Arel::Nodes::Matches, + Arel::Nodes::NotEqual, + Arel::Nodes::NotIn, + Arel::Nodes::Or, + Arel::Nodes::TableAlias, + Arel::Nodes::Values, + Arel::Nodes::As, + Arel::Nodes::DeleteStatement, + Arel::Nodes::JoinSource, + ].each do |klass| + define_method("test_#{klass.name.gsub('::', '_')}") do + binary = klass.new(:a, :b) + @visitor.accept binary, Collectors::PlainString.new + end + end + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_ibm_db.rb ruby-arel-6.0.4/test/visitors/test_ibm_db.rb --- ruby-arel-6.0.3/test/visitors/test_ibm_db.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_ibm_db.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,33 @@ +require 'helper' + +module Arel + module Visitors + describe 'the ibm_db visitor' do + before do + @visitor = IBM_DB.new Table.engine.connection + end + + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + + it 'uses FETCH FIRST n ROWS to limit results' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(1) + sql = compile(stmt) + sql.must_be_like "SELECT FETCH FIRST 1 ROWS ONLY" + end + + it 'uses FETCH FIRST n ROWS in updates with a limit' do + table = Table.new(:users) + stmt = Nodes::UpdateStatement.new + stmt.relation = table + stmt.limit = Nodes::Limit.new(Nodes.build_quoted(1)) + stmt.key = table[:id] + sql = compile(stmt) + sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT \"users\".\"id\" FROM \"users\" FETCH FIRST 1 ROWS ONLY)" + end + + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_informix.rb ruby-arel-6.0.4/test/visitors/test_informix.rb --- ruby-arel-6.0.3/test/visitors/test_informix.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_informix.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,58 @@ +require 'helper' + +module Arel + module Visitors + describe 'the informix visitor' do + before do + @visitor = Informix.new Table.engine.connection + end + + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + + it 'uses FIRST n to limit results' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(1) + sql = compile(stmt) + sql.must_be_like "SELECT FIRST 1" + end + + it 'uses FIRST n in updates with a limit' do + table = Table.new(:users) + stmt = Nodes::UpdateStatement.new + stmt.relation = table + stmt.limit = Nodes::Limit.new(Nodes.build_quoted(1)) + stmt.key = table[:id] + sql = compile(stmt) + sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT FIRST 1 \"users\".\"id\" FROM \"users\")" + end + + it 'uses SKIP n to jump results' do + stmt = Nodes::SelectStatement.new + stmt.offset = Nodes::Offset.new(10) + sql = compile(stmt) + sql.must_be_like "SELECT SKIP 10" + end + + it 'uses SKIP before FIRST' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(1) + stmt.offset = Nodes::Offset.new(1) + sql = compile(stmt) + sql.must_be_like "SELECT SKIP 1 FIRST 1" + end + + it 'uses INNER JOIN to perform joins' do + core = Nodes::SelectCore.new + table = Table.new(:posts) + core.source = Nodes::JoinSource.new(table, [table.create_join(Table.new(:comments))]) + + stmt = Nodes::SelectStatement.new([core]) + sql = compile(stmt) + sql.must_be_like 'SELECT FROM "posts" INNER JOIN "comments"' + end + + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_mssql.rb ruby-arel-6.0.4/test/visitors/test_mssql.rb --- ruby-arel-6.0.3/test/visitors/test_mssql.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_mssql.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,70 @@ +require 'helper' + +module Arel + module Visitors + describe 'the mssql visitor' do + before do + @visitor = MSSQL.new Table.engine.connection + @table = Arel::Table.new "users" + end + + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + + it 'should not modify query if no offset or limit' do + stmt = Nodes::SelectStatement.new + sql = compile(stmt) + sql.must_be_like "SELECT" + end + + it 'should go over table PK if no .order() or .group()' do + stmt = Nodes::SelectStatement.new + stmt.cores.first.from = @table + stmt.limit = Nodes::Limit.new(10) + sql = compile(stmt) + 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 'should go over query ORDER BY if .order()' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(10) + stmt.orders << Nodes::SqlLiteral.new('order_by') + sql = compile(stmt) + sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY order_by) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10" + end + + it 'should go over query GROUP BY if no .order() and there is .group()' do + stmt = Nodes::SelectStatement.new + stmt.cores.first.groups << Nodes::SqlLiteral.new('group_by') + stmt.limit = Nodes::Limit.new(10) + sql = compile(stmt) + sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY group_by) as _row_num GROUP BY group_by) as _t WHERE _row_num BETWEEN 1 AND 10" + end + + it 'should use BETWEEN if both .limit() and .offset' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(10) + stmt.offset = Nodes::Offset.new(20) + sql = compile(stmt) + sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 21 AND 30" + end + + it 'should use >= if only .offset' do + stmt = Nodes::SelectStatement.new + stmt.offset = Nodes::Offset.new(20) + sql = compile(stmt) + sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num >= 21" + end + + it 'should generate subquery for .count' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(10) + stmt.cores.first.projections << Nodes::Count.new('*') + sql = compile(stmt) + sql.must_be_like "SELECT COUNT(1) as count_id FROM (SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10) AS subquery" + end + + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_mysql.rb ruby-arel-6.0.4/test/visitors/test_mysql.rb --- ruby-arel-6.0.3/test/visitors/test_mysql.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_mysql.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,60 @@ +require 'helper' + +module Arel + module Visitors + describe 'the mysql visitor' do + before do + @visitor = MySQL.new Table.engine.connection + end + + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + + it 'squashes parenthesis on multiple unions' do + subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right') + node = Nodes::Union.new subnode, Arel.sql('topright') + assert_equal 1, compile(node).scan('(').length + + subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right') + node = Nodes::Union.new Arel.sql('topleft'), subnode + assert_equal 1, compile(node).scan('(').length + end + + ### + # :'( + # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 + it 'defaults limit to 18446744073709551615' do + stmt = Nodes::SelectStatement.new + stmt.offset = Nodes::Offset.new(1) + sql = compile(stmt) + sql.must_be_like "SELECT FROM DUAL LIMIT 18446744073709551615 OFFSET 1" + end + + it "should escape LIMIT" do + sc = Arel::Nodes::UpdateStatement.new + sc.relation = Table.new(:users) + sc.limit = Nodes::Limit.new(Nodes.build_quoted("omg")) + assert_equal("UPDATE \"users\" LIMIT 'omg'", compile(sc)) + end + + it 'uses DUAL for empty from' do + stmt = Nodes::SelectStatement.new + sql = compile(stmt) + sql.must_be_like "SELECT FROM DUAL" + end + + describe 'locking' do + it 'defaults to FOR UPDATE when locking' do + node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) + compile(node).must_be_like "FOR UPDATE" + end + + it 'allows a custom string to be used as a lock' do + node = Nodes::Lock.new(Arel.sql('LOCK IN SHARE MODE')) + compile(node).must_be_like "LOCK IN SHARE MODE" + end + end + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_oracle.rb ruby-arel-6.0.4/test/visitors/test_oracle.rb --- ruby-arel-6.0.3/test/visitors/test_oracle.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_oracle.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,181 @@ +require 'helper' + +module Arel + module Visitors + describe 'the oracle visitor' do + before do + @visitor = Oracle.new Table.engine.connection + @table = Table.new(:users) + end + + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + + it 'modifies order when there is distinct and first value' do + # *sigh* + select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__" + stmt = Nodes::SelectStatement.new + stmt.cores.first.projections << Nodes::SqlLiteral.new(select) + stmt.orders << Nodes::SqlLiteral.new('foo') + sql = compile(stmt) + sql.must_be_like %{ + SELECT #{select} ORDER BY alias_0__ + } + end + + it 'is idempotent with crazy query' do + # *sigh* + select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__" + stmt = Nodes::SelectStatement.new + stmt.cores.first.projections << Nodes::SqlLiteral.new(select) + stmt.orders << Nodes::SqlLiteral.new('foo') + + sql = compile(stmt) + sql2 = compile(stmt) + sql.must_equal sql2 + end + + it 'splits orders with commas' do + # *sigh* + select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__" + stmt = Nodes::SelectStatement.new + stmt.cores.first.projections << Nodes::SqlLiteral.new(select) + stmt.orders << Nodes::SqlLiteral.new('foo, bar') + sql = compile(stmt) + sql.must_be_like %{ + SELECT #{select} ORDER BY alias_0__, alias_1__ + } + end + + it 'splits orders with commas and function calls' do + # *sigh* + select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__" + stmt = Nodes::SelectStatement.new + stmt.cores.first.projections << Nodes::SqlLiteral.new(select) + stmt.orders << Nodes::SqlLiteral.new('NVL(LOWER(bar, foo), foo) DESC, UPPER(baz)') + sql = compile(stmt) + sql.must_be_like %{ + SELECT #{select} ORDER BY alias_0__ DESC, alias_1__ + } + end + + describe 'Nodes::SelectStatement' do + describe 'limit' do + it 'adds a rownum clause' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(10) + sql = compile stmt + sql.must_be_like %{ SELECT WHERE ROWNUM <= 10 } + end + + it 'is idempotent' do + stmt = Nodes::SelectStatement.new + stmt.orders << Nodes::SqlLiteral.new('foo') + stmt.limit = Nodes::Limit.new(10) + sql = compile stmt + sql2 = compile stmt + sql.must_equal sql2 + end + + it 'creates a subquery when there is order_by' do + stmt = Nodes::SelectStatement.new + stmt.orders << Nodes::SqlLiteral.new('foo') + stmt.limit = Nodes::Limit.new(10) + sql = compile stmt + sql.must_be_like %{ + SELECT * FROM (SELECT ORDER BY foo ) WHERE ROWNUM <= 10 + } + end + + it 'creates a subquery when there is group by' do + stmt = Nodes::SelectStatement.new + stmt.cores.first.groups << Nodes::SqlLiteral.new('foo') + stmt.limit = Nodes::Limit.new(10) + sql = compile stmt + sql.must_be_like %{ + SELECT * FROM (SELECT GROUP BY foo ) WHERE ROWNUM <= 10 + } + end + + it 'creates a subquery when there is DISTINCT' do + stmt = Nodes::SelectStatement.new + stmt.cores.first.set_quantifier = Arel::Nodes::Distinct.new + stmt.cores.first.projections << Nodes::SqlLiteral.new('id') + stmt.limit = Arel::Nodes::Limit.new(10) + sql = compile stmt + sql.must_be_like %{ + SELECT * FROM (SELECT DISTINCT id ) WHERE ROWNUM <= 10 + } + end + + it 'creates a different subquery when there is an offset' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(10) + stmt.offset = Nodes::Offset.new(10) + sql = compile stmt + sql.must_be_like %{ + SELECT * FROM ( + SELECT raw_sql_.*, rownum raw_rnum_ + FROM (SELECT ) raw_sql_ + WHERE rownum <= 20 + ) + WHERE raw_rnum_ > 10 + } + end + + it 'is idempotent with different subquery' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(10) + stmt.offset = Nodes::Offset.new(10) + sql = compile stmt + sql2 = compile stmt + sql.must_equal sql2 + end + end + + describe 'only offset' do + it 'creates a select from subquery with rownum condition' do + stmt = Nodes::SelectStatement.new + stmt.offset = Nodes::Offset.new(10) + sql = compile stmt + sql.must_be_like %{ + SELECT * FROM ( + SELECT raw_sql_.*, rownum raw_rnum_ + FROM (SELECT) raw_sql_ + ) + WHERE raw_rnum_ > 10 + } + end + end + + 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 + + describe 'locking' do + 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 + + 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 -Nru ruby-arel-6.0.3/test/visitors/test_postgres.rb ruby-arel-6.0.4/test/visitors/test_postgres.rb --- ruby-arel-6.0.3/test/visitors/test_postgres.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_postgres.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,132 @@ +require 'helper' + +module Arel + module Visitors + describe 'the postgres visitor' do + before do + @visitor = PostgreSQL.new Table.engine.connection + @table = Table.new(:users) + @attr = @table[:id] + end + + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + + describe 'locking' do + it 'defaults to FOR UPDATE' do + compile(Nodes::Lock.new(Arel.sql('FOR UPDATE'))).must_be_like %{ + FOR UPDATE + } + end + + it 'allows a custom string to be used as a lock' do + node = Nodes::Lock.new(Arel.sql('FOR SHARE')) + compile(node).must_be_like %{ + FOR SHARE + } + end + end + + it "should escape LIMIT" do + sc = Arel::Nodes::SelectStatement.new + sc.limit = Nodes::Limit.new(Nodes.build_quoted("omg")) + sc.cores.first.projections << Arel.sql('DISTINCT ON') + sc.orders << Arel.sql("xyz") + sql = compile(sc) + assert_match(/LIMIT 'omg'/, sql) + assert_equal 1, sql.scan(/LIMIT/).length, 'should have one limit' + end + + it 'should support DISTINCT ON' do + core = Arel::Nodes::SelectCore.new + core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql('aaron')) + assert_match 'DISTINCT ON ( aaron )', compile(core) + end + + it 'should support DISTINCT' do + core = Arel::Nodes::SelectCore.new + core.set_quantifier = Arel::Nodes::Distinct.new + assert_equal 'SELECT DISTINCT', compile(core) + end + + describe "Nodes::Matches" do + it "should know how to visit" do + node = @table[:name].matches('foo%') + compile(node).must_be_like %{ + "users"."name" ILIKE 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(@table[:name].matches('foo%')) + node = @attr.in subquery + compile(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') + } + end + end + + describe "Nodes::DoesNotMatch" do + it "should know how to visit" do + node = @table[:name].does_not_match('foo%') + compile(node).must_be_like %{ + "users"."name" NOT ILIKE 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) + node = @attr.in subquery + compile(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT ILIKE 'foo%') + } + end + end + + describe "Nodes::Regexp" do + it "should know how to visit" do + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')) + 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%'))) + node = @attr.in subquery + compile(node).must_be_like %{ + "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%')) + compile(node).must_be_like %{ + "users"."name" !~ 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'))) + node = @attr.in subquery + compile(node).must_be_like %{ + "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 + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_sqlite.rb ruby-arel-6.0.4/test/visitors/test_sqlite.rb --- ruby-arel-6.0.3/test/visitors/test_sqlite.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_sqlite.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,23 @@ +require 'helper' + +module Arel + module Visitors + describe 'the sqlite visitor' do + before do + @visitor = SQLite.new Table.engine.connection_pool + end + + it 'defaults limit to -1' do + stmt = Nodes::SelectStatement.new + stmt.offset = Nodes::Offset.new(1) + sql = @visitor.accept(stmt, Collectors::SQLString.new).value + sql.must_be_like "SELECT LIMIT -1 OFFSET 1" + end + + it 'does not support locking' do + node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) + assert_equal '', @visitor.accept(node, Collectors::SQLString.new).value + end + end + end +end diff -Nru ruby-arel-6.0.3/test/visitors/test_to_sql.rb ruby-arel-6.0.4/test/visitors/test_to_sql.rb --- ruby-arel-6.0.3/test/visitors/test_to_sql.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/test/visitors/test_to_sql.rb 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,605 @@ +require 'helper' +require 'set' + +module Arel + module Visitors + describe 'the to_sql visitor' do + before do + @conn = FakeRecord::Base.new + @visitor = ToSql.new @conn.connection + @table = Table.new(:users) + @attr = @table[:id] + end + + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + + it 'works with BindParams' do + node = Nodes::BindParam.new + sql = compile node + 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 + visited = false + viz = Class.new(Arel::Visitors::Reduce) { + define_method(:hello) do |node, c| + visited = true + end + + def dispatch + { Arel::Table => 'hello' } + end + }.new + + viz.accept(@table, Collectors::SQLString.new) + assert visited, 'hello method was called' + end + + it 'should not quote sql literals' do + node = @table[Arel.star] + sql = compile node + sql.must_be_like '"users".*' + end + + it 'should visit named functions' do + function = Nodes::NamedFunction.new('omg', [Arel.star]) + assert_equal 'omg(*)', compile(function) + end + + it 'should chain predications on named functions' do + function = Nodes::NamedFunction.new('omg', [Arel.star]) + sql = compile(function.eq(2)) + sql.must_be_like %{ omg(*) = 2 } + end + + it 'should visit built-in functions' do + function = Nodes::Count.new([Arel.star]) + assert_equal 'COUNT(*)', compile(function) + + function = Nodes::Sum.new([Arel.star]) + assert_equal 'SUM(*)', compile(function) + + function = Nodes::Max.new([Arel.star]) + assert_equal 'MAX(*)', compile(function) + + function = Nodes::Min.new([Arel.star]) + assert_equal 'MIN(*)', compile(function) + + function = Nodes::Avg.new([Arel.star]) + assert_equal 'AVG(*)', compile(function) + end + + it 'should visit built-in functions operating on distinct values' do + function = Nodes::Count.new([Arel.star]) + function.distinct = true + assert_equal 'COUNT(DISTINCT *)', compile(function) + + function = Nodes::Sum.new([Arel.star]) + function.distinct = true + assert_equal 'SUM(DISTINCT *)', compile(function) + + function = Nodes::Max.new([Arel.star]) + function.distinct = true + assert_equal 'MAX(DISTINCT *)', compile(function) + + function = Nodes::Min.new([Arel.star]) + function.distinct = true + assert_equal 'MIN(DISTINCT *)', compile(function) + + function = Nodes::Avg.new([Arel.star]) + function.distinct = true + assert_equal 'AVG(DISTINCT *)', compile(function) + end + + it 'works with lists' do + function = Nodes::NamedFunction.new('omg', [Arel.star, Arel.star]) + assert_equal 'omg(*, *)', compile(function) + end + + describe 'Nodes::Equality' do + it "should escape strings" do + test = Table.new(:users)[:name].eq 'Aaron Patterson' + compile(test).must_be_like %{ + "users"."name" = 'Aaron Patterson' + } + end + + it 'should handle false' do + table = Table.new(:users) + val = Nodes.build_quoted(false, table[:active]) + sql = compile Nodes::Equality.new(val, val) + sql.must_be_like %{ 'f' = 'f' } + end + + it 'should use the column to quote' do + table = Table.new(:users) + val = Nodes.build_quoted('1-fooo', table[:id]) + sql = compile Nodes::Equality.new(table[:id], val) + sql.must_be_like %{ "users"."id" = 1 } + end + + it 'should use the column to quote integers' do + table = Table.new(:users) + sql = compile table[:name].eq(0) + sql.must_be_like %{ "users"."name" = '0' } + end + + it 'should handle nil' do + sql = compile Nodes::Equality.new(@table[:name], nil) + sql.must_be_like %{ "users"."name" IS NULL } + end + end + + describe 'Nodes::Grouping' do + it 'wraps nested groupings in brackets only once' do + sql = compile Nodes::Grouping.new(Nodes::Grouping.new(Nodes.build_quoted('foo'))) + sql.must_equal "('foo')" + end + end + + describe 'Nodes::NotEqual' do + it 'should handle false' do + val = Nodes.build_quoted(false, @table[:active]) + sql = compile Nodes::NotEqual.new(@table[:active], val) + sql.must_be_like %{ "users"."active" != 'f' } + end + + it 'should handle nil' do + val = Nodes.build_quoted(nil, @table[:active]) + sql = compile Nodes::NotEqual.new(@table[:name], val) + sql.must_be_like %{ "users"."name" IS NOT NULL } + end + end + + it "should visit string subclass" do + [ + Class.new(String).new(":'("), + Class.new(Class.new(String)).new(":'("), + ].each do |obj| + val = Nodes.build_quoted(obj, @table[:active]) + sql = compile Nodes::NotEqual.new(@table[:name], val) + sql.must_be_like %{ "users"."name" != ':\\'(' } + end + end + + it "should visit_Class" do + compile(Nodes.build_quoted(DateTime)).must_equal "'DateTime'" + end + + it "should escape LIMIT" do + sc = Arel::Nodes::SelectStatement.new + sc.limit = Arel::Nodes::Limit.new(Nodes.build_quoted("omg")) + assert_match(/LIMIT 'omg'/, compile(sc)) + end + + it "should quote LIMIT without column type coercion" do + table = Table.new(:users) + sc = table.where(table[:name].eq(0)).take(1).ast + assert_match(/WHERE "users"."name" = '0' LIMIT 1/, compile(sc)) + end + + it "should visit_DateTime" do + called_with = nil + @conn.connection.extend(Module.new { + define_method(:quote) do |thing, column| + called_with = column + super(thing, column) + end + }) + + dt = DateTime.now + table = Table.new(:users) + test = table[:created_at].eq dt + sql = compile test + + assert_equal "created_at", called_with.name + sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d %H:%M:%S")}'} + end + + it "should visit_Float" do + test = Table.new(:products)[:price].eq 2.14 + sql = compile test + sql.must_be_like %{"products"."price" = 2.14} + end + + it "should visit_Not" do + sql = compile Nodes::Not.new(Arel.sql("foo")) + sql.must_be_like "NOT (foo)" + end + + it "should apply Not to the whole expression" do + node = Nodes::And.new [@attr.eq(10), @attr.eq(11)] + sql = compile Nodes::Not.new(node) + sql.must_be_like %{NOT ("users"."id" = 10 AND "users"."id" = 11)} + end + + it "should visit_As" do + as = Nodes::As.new(Arel.sql("foo"), Arel.sql("bar")) + sql = compile as + sql.must_be_like "foo AS bar" + end + + it "should visit_Bignum" do + compile 8787878092 + end + + it "should visit_Hash" do + compile(Nodes.build_quoted({:a => 1})) + end + + it "should visit_Set" do + compile Nodes.build_quoted(Set.new([1, 2])) + end + + it "should visit_BigDecimal" do + compile Nodes.build_quoted(BigDecimal.new('2.14')) + end + + it "should visit_Date" do + called_with = nil + @conn.connection.extend(Module.new { + define_method(:quote) do |thing, column| + called_with = column + super(thing, column) + end + }) + + dt = Date.today + table = Table.new(:users) + test = table[:created_at].eq dt + sql = compile test + + assert_equal "created_at", called_with.name + sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d")}'} + end + + it "should visit_NilClass" do + 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) + end + + it "should visit_Arel_SelectManager, which is a subquery" do + mgr = Table.new(:foo).project(:bar) + compile(mgr).must_be_like '(SELECT bar FROM "foo")' + end + + it "should visit_Arel_Nodes_And" do + node = Nodes::And.new [@attr.eq(10), @attr.eq(11)] + compile(node).must_be_like %{ + "users"."id" = 10 AND "users"."id" = 11 + } + end + + it "should visit_Arel_Nodes_Or" do + node = Nodes::Or.new @attr.eq(10), @attr.eq(11) + compile(node).must_be_like %{ + "users"."id" = 10 OR "users"."id" = 11 + } + end + + it "should visit_Arel_Nodes_Assignment" do + column = @table["id"] + node = Nodes::Assignment.new( + Nodes::UnqualifiedColumn.new(column), + Nodes::UnqualifiedColumn.new(column) + ) + compile(node).must_be_like %{ + "id" = "id" + } + end + + it "should visit visit_Arel_Attributes_Time" do + attr = Attributes::Time.new(@attr.relation, @attr.name) + compile attr + end + + it "should visit_TrueClass" do + test = Table.new(:users)[:bool].eq(true) + compile(test).must_be_like %{ "users"."bool" = 't' } + end + + describe "Nodes::Matches" do + it "should know how to visit" do + node = @table[:name].matches('foo%') + 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" LIKE 'foo!%' ESCAPE '!' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(@table[:name].matches('foo%')) + node = @attr.in subquery + compile(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" LIKE 'foo%') + } + end + end + + describe "Nodes::DoesNotMatch" do + it "should know how to visit" do + node = @table[:name].does_not_match('foo%') + 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 LIKE 'foo!%' ESCAPE '!' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) + node = @attr.in subquery + compile(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT LIKE 'foo%') + } + end + end + + describe "Nodes::Ordering" do + it "should know how to visit" do + node = @attr.desc + compile(node).must_be_like %{ + "users"."id" DESC + } + end + end + + describe "Nodes::In" do + it "should know how to visit" do + node = @attr.in [1, 2, 3] + compile(node).must_be_like %{ + "users"."id" IN (1, 2, 3) + } + end + + it "should return 1=0 when empty right which is always false" do + node = @attr.in [] + compile(node).must_equal '1=0' + end + + it 'can handle two dot ranges' do + 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.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.between 1..Float::INFINITY + compile(node).must_be_like %{ + "users"."id" >= 1 + } + node = @attr.between(-Float::INFINITY..3) + compile(node).must_be_like %{ + "users"."id" <= 3 + } + node = @attr.between(-Float::INFINITY...3) + compile(node).must_be_like %{ + "users"."id" < 3 + } + node = @attr.between(-Float::INFINITY..Float::INFINITY) + compile(node).must_be_like %{1=1} + end + + it 'can handle subqueries' do + table = Table.new(:users) + subquery = table.project(:id).where(table[:name].eq('Aaron')) + node = @attr.in subquery + compile(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') + } + end + + it 'uses the same column for escaping values' do + @attr = Table.new(:users)[:name] + visitor = Class.new(ToSql) do + attr_accessor :expected + + def quote value, column = nil + raise unless column == expected + super + end + end + vals = %w{ a b c }.map { |x| Nodes.build_quoted(x, @attr) } + in_node = Nodes::In.new @attr, vals + visitor = visitor.new(Table.engine.connection) + visitor.expected = Table.engine.connection.columns(:users).find { |x| + x.name == 'name' + } + visitor.accept(in_node, Collectors::SQLString.new).value.must_equal %("users"."name" IN ('a', 'b', 'c')) + end + end + + describe "Nodes::InfixOperation" do + it "should handle Multiplication" do + node = Arel::Attributes::Decimal.new(Table.new(:products), :price) * Arel::Attributes::Decimal.new(Table.new(:currency_rates), :rate) + compile(node).must_equal %("products"."price" * "currency_rates"."rate") + end + + it "should handle Division" do + node = Arel::Attributes::Decimal.new(Table.new(:products), :price) / 5 + compile(node).must_equal %("products"."price" / 5) + end + + it "should handle Addition" do + node = Arel::Attributes::Decimal.new(Table.new(:products), :price) + 6 + compile(node).must_equal %(("products"."price" + 6)) + end + + it "should handle Subtraction" do + node = Arel::Attributes::Decimal.new(Table.new(:products), :price) - 7 + compile(node).must_equal %(("products"."price" - 7)) + end + + it "should handle arbitrary operators" do + node = Arel::Nodes::InfixOperation.new( + '||', + Arel::Attributes::String.new(Table.new(:products), :name), + Arel::Attributes::String.new(Table.new(:products), :name) + ) + compile(node).must_equal %("products"."name" || "products"."name") + end + end + + describe "Nodes::NotIn" do + it "should know how to visit" do + node = @attr.not_in [1, 2, 3] + compile(node).must_be_like %{ + "users"."id" NOT IN (1, 2, 3) + } + end + + it "should return 1=1 when empty right which is always true" do + node = @attr.not_in [] + compile(node).must_equal '1=1' + end + + it 'can handle two dot ranges' do + 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_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_between 1..Float::INFINITY + compile(node).must_be_like %{ + "users"."id" < 1 + } + node = @attr.not_between(-Float::INFINITY..3) + compile(node).must_be_like %{ + "users"."id" > 3 + } + node = @attr.not_between(-Float::INFINITY...3) + compile(node).must_be_like %{ + "users"."id" >= 3 + } + node = @attr.not_between(-Float::INFINITY..Float::INFINITY) + compile(node).must_be_like %{1=0} + end + + it 'can handle subqueries' do + table = Table.new(:users) + subquery = table.project(:id).where(table[:name].eq('Aaron')) + node = @attr.not_in subquery + compile(node).must_be_like %{ + "users"."id" NOT IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') + } + end + + it 'uses the same column for escaping values' do + @attr = Table.new(:users)[:name] + visitor = Class.new(ToSql) do + attr_accessor :expected + + def quote value, column = nil + raise unless column == expected + super + end + end + vals = %w{ a b c }.map { |x| Nodes.build_quoted(x, @attr) } + in_node = Nodes::NotIn.new @attr, vals + visitor = visitor.new(Table.engine.connection) + visitor.expected = Table.engine.connection.columns(:users).find { |x| + x.name == 'name' + } + compile(in_node).must_equal %("users"."name" NOT IN ('a', 'b', 'c')) + end + end + + describe 'Constants' do + it "should handle true" do + test = Table.new(:users).create_true + compile(test).must_be_like %{ + TRUE + } + end + + it "should handle false" do + test = Table.new(:users).create_false + compile(test).must_be_like %{ + FALSE + } + end + end + + describe 'TableAlias' do + it "should use the underlying table for checking columns" do + test = Table.new(:users).alias('zomgusers')[:id].eq '3' + compile(test).must_be_like %{ + "zomgusers"."id" = 3 + } + end + end + + describe 'distinct on' do + it 'raises not implemented error' do + core = Arel::Nodes::SelectCore.new + core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql('aaron')) + + assert_raises(NotImplementedError) do + compile(core) + end + end + end + + describe 'Nodes::Regexp' do + it 'raises not implemented error' do + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')) + + assert_raises(NotImplementedError) do + compile(node) + end + end + end + + describe 'Nodes::NotRegexp' do + it 'raises not implemented error' do + node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')) + + assert_raises(NotImplementedError) do + compile(node) + end + end + end + end + end +end diff -Nru ruby-arel-6.0.3/.travis.yml ruby-arel-6.0.4/.travis.yml --- ruby-arel-6.0.3/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-arel-6.0.4/.travis.yml 2016-12-27 13:51:36.000000000 +0000 @@ -0,0 +1,28 @@ +language: ruby +sudo: false +cache: bundler +script: + - "bundle exec rake test" + - "gem build arel.gemspec" +rvm: + - rbx + - jruby + - 1.9.3 + - 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="