arel-4.0.0/0000755000004100000410000000000012161114331012457 5ustar www-datawww-dataarel-4.0.0/.travis.yml0000644000004100000410000000023412161114331014567 0ustar www-datawww-datascript: "rake test" rvm: - rbx-19mode - jruby - 1.9.2 - 1.9.3 - 2.0.0 notifications: email: false irc: - "irc.freenode.org#rails-contrib" arel-4.0.0/test/0000755000004100000410000000000012161114331013436 5ustar www-datawww-dataarel-4.0.0/test/nodes/0000755000004100000410000000000012161114331014546 5ustar www-datawww-dataarel-4.0.0/test/nodes/test_or.rb0000644000004100000410000000153712161114331016560 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_select_core.rb0000644000004100000410000000417312161114331020426 0ustar www-datawww-datarequire 'helper' module Arel module Nodes class TestSelectCore < MiniTest::Unit::TestCase 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 dolly.froms.must_equal core.froms dolly.projections.must_equal core.projections dolly.wheres.must_equal core.wheres dolly.froms.wont_be_same_as core.froms dolly.projections.wont_be_same_as core.projections dolly.wheres.wont_be_same_as core.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) 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 arel-4.0.0/test/nodes/test_not.rb0000644000004100000410000000124412161114331016733 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_delete_statement.rb0000644000004100000410000000172512161114331021465 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_window.rb0000644000004100000410000000356512161114331017452 0ustar www-datawww-datarequire '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.frame 3 window2 = Window.new window2.orders = [1, 2] 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.frame 3 window2 = Window.new window2.orders = [1, 2] 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.frame 3 window2 = NamedWindow.new 'foo' window2.orders = [1, 2] 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.frame 3 window2 = NamedWindow.new 'bar' window2.orders = [1, 2] 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 arel-4.0.0/test/nodes/test_true.rb0000644000004100000410000000062512161114331017114 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_distinct.rb0000644000004100000410000000065012161114331017754 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_update_statement.rb0000644000004100000410000000340212161114331021477 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_node.rb0000644000004100000410000000162012161114331017056 0ustar www-datawww-datarequire 'helper' module Arel class TestNode < MiniTest::Unit::TestCase 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 arel-4.0.0/test/nodes/test_named_function.rb0000644000004100000410000000250512161114331021125 0ustar www-datawww-datarequire 'helper' module Arel module Nodes class TestNamedFunction < MiniTest::Unit::TestCase 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 arel-4.0.0/test/nodes/test_ascending.rb0000644000004100000410000000213612161114331020067 0ustar www-datawww-datarequire 'helper' module Arel module Nodes class TestAscending < MiniTest::Unit::TestCase 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 arel-4.0.0/test/nodes/test_grouping.rb0000644000004100000410000000114512161114331017765 0ustar www-datawww-datarequire 'helper' module Arel module Nodes describe 'Grouping' do it 'should create Equality nodes' do grouping = Grouping.new('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 arel-4.0.0/test/nodes/test_and.rb0000644000004100000410000000072012161114331016673 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_descending.rb0000644000004100000410000000216012161114331020234 0ustar www-datawww-datarequire 'helper' module Arel module Nodes class TestDescending < MiniTest::Unit::TestCase 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 arel-4.0.0/test/nodes/test_sum.rb0000644000004100000410000000113512161114331016736 0ustar www-datawww-datarequire '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 end arel-4.0.0/test/nodes/test_insert_statement.rb0000644000004100000410000000240612161114331021524 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_infix_operation.rb0000644000004100000410000000221512161114331021327 0ustar www-datawww-datarequire 'helper' module Arel module Nodes class TestInfixOperation < MiniTest::Unit::TestCase 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_opertaion_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 arel-4.0.0/test/nodes/test_table_alias.rb0000644000004100000410000000203512161114331020372 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_equality.rb0000644000004100000410000000450412161114331017772 0ustar www-datawww-datarequire '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 2 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 arel-4.0.0/test/nodes/test_select_statement.rb0000644000004100000410000000270712161114331021503 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_bin.rb0000644000004100000410000000160412161114331016703 0ustar www-datawww-datarequire 'helper' module Arel module Nodes class TestBin < MiniTest::Unit::TestCase 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) 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) 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 arel-4.0.0/test/nodes/test_count.rb0000644000004100000410000000172312161114331017265 0ustar www-datawww-datarequire 'helper' describe Arel::Nodes::Count do describe 'backwards compatibility' do it 'must be an expression' do Arel::Nodes::Count.new('foo').must_be_kind_of Arel::Expression end end 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 arel-4.0.0/test/nodes/test_sql_literal.rb0000644000004100000410000000330512161114331020446 0ustar www-datawww-datarequire 'helper' module Arel module Nodes describe 'sql literal' do before do @visitor = Visitors::ToSql.new Table.engine.connection_pool 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 @visitor.accept(node).must_be_like %{ COUNT(*) } end it 'makes a distinct node' do node = SqlLiteral.new('*').count true @visitor.accept(node).must_be_like %{ COUNT(DISTINCT *) } end end describe 'equality' do it 'makes an equality node' do node = SqlLiteral.new('foo').eq(1) @visitor.accept(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]) @visitor.accept(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]) @visitor.accept(node).must_be_like %{ (foo = 1 AND foo = 2) } end end end end end arel-4.0.0/test/nodes/test_extract.rb0000644000004100000410000000161712161114331017611 0ustar www-datawww-datarequire '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 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 arel-4.0.0/test/nodes/test_over.rb0000644000004100000410000000333512161114331017111 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_false.rb0000644000004100000410000000063112161114331017224 0ustar www-datawww-datarequire '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 arel-4.0.0/test/nodes/test_as.rb0000644000004100000410000000156512161114331016544 0ustar www-datawww-datarequire '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 arel-4.0.0/test/test_factory_methods.rb0000644000004100000410000000202012161114331020206 0ustar www-datawww-datarequire 'helper' module Arel module FactoryMethods class TestFactoryMethods < MiniTest::Unit::TestCase 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 end end end end arel-4.0.0/test/test_attributes.rb0000644000004100000410000000377312161114331017222 0ustar www-datawww-datarequire '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 arel-4.0.0/test/helper.rb0000644000004100000410000000044512161114331015245 0ustar www-datawww-datarequire 'rubygems' require 'minitest/autorun' require 'fileutils' require 'arel' require 'support/fake_record' Arel::Table.engine = Arel::Sql::Engine.new(FakeRecord::Base.new) class Object def must_be_like other gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip end end arel-4.0.0/test/visitors/0000755000004100000410000000000012161114331015320 5ustar www-datawww-dataarel-4.0.0/test/visitors/test_join_sql.rb0000644000004100000410000000220412161114331020520 0ustar www-datawww-datarequire 'helper' module Arel module Visitors describe 'the join_sql visitor' do before do @visitor = ToSql.new Table.engine.connection @visitor.extend(JoinSql) end it 'should visit string join' do sql = @visitor.accept Nodes::StringJoin.new('omg') sql.must_be_like "'omg'" end describe 'inner join' do it 'should visit left if left is a join' do t = Table.new :users sm = t.select_manager sm.join(t).on(t[:id]).join(t).on(t[:id]) sm.join_sql.must_be_like %{ INNER JOIN "users" ON "users"."id" INNER JOIN "users" ON "users"."id" } end end describe 'outer join' do it 'should visit left if left is a join' do t = Table.new :users sm = t.select_manager sm.join(t, Nodes::OuterJoin).on(t[:id]).join( t, Nodes::OuterJoin).on(t[:id]) sm.join_sql.must_be_like %{ LEFT OUTER JOIN "users" ON "users"."id" LEFT OUTER JOIN "users" ON "users"."id" } end end end end end arel-4.0.0/test/visitors/test_postgres.rb0000644000004100000410000000261512161114331020556 0ustar www-datawww-datarequire 'helper' module Arel module Visitors describe 'the postgres visitor' do before do @visitor = PostgreSQL.new Table.engine.connection end describe 'locking' do it 'defaults to FOR UPDATE' do @visitor.accept(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')) @visitor.accept(node).must_be_like %{ FOR SHARE } end end it "should escape LIMIT" do sc = Arel::Nodes::SelectStatement.new sc.limit = Nodes::Limit.new("omg") sc.cores.first.projections << 'DISTINCT ON' sc.orders << "xyz" sql = @visitor.accept(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 )', @visitor.accept(core) end it 'should support DISTINCT' do core = Arel::Nodes::SelectCore.new core.set_quantifier = Arel::Nodes::Distinct.new assert_equal 'SELECT DISTINCT', @visitor.accept(core) end end end end arel-4.0.0/test/visitors/test_informix.rb0000644000004100000410000000300312161114331020533 0ustar www-datawww-datarequire 'helper' module Arel module Visitors describe 'the informix visitor' do before do @visitor = Informix.new Table.engine.connection end it 'uses LIMIT n to limit results' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) sql = @visitor.accept(stmt) sql.must_be_like "SELECT LIMIT 1" end it 'uses LIMIT n in updates with a limit' do stmt = Nodes::UpdateStatement.new stmt.limit = Nodes::Limit.new(1) stmt.key = 'id' sql = @visitor.accept(stmt) sql.must_be_like "UPDATE NULL WHERE 'id' IN (SELECT LIMIT 1 'id')" end it 'uses SKIP n to jump results' do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(10) sql = @visitor.accept(stmt) sql.must_be_like "SELECT SKIP 10" end it 'uses SKIP before LIMIT' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) stmt.offset = Nodes::Offset.new(1) sql = @visitor.accept(stmt) sql.must_be_like "SELECT SKIP 1 LIMIT 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 = @visitor.accept(stmt) sql.must_be_like 'SELECT FROM "posts" INNER JOIN "comments"' end end end end arel-4.0.0/test/visitors/test_ibm_db.rb0000644000004100000410000000133612161114331020123 0ustar www-datawww-datarequire 'helper' module Arel module Visitors describe 'the ibm_db visitor' do before do @visitor = IBM_DB.new Table.engine.connection end it 'uses FETCH FIRST n ROWS to limit results' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) sql = @visitor.accept(stmt) sql.must_be_like "SELECT FETCH FIRST 1 ROWS ONLY" end it 'uses FETCH FIRST n ROWS in updates with a limit' do stmt = Nodes::UpdateStatement.new stmt.limit = Nodes::Limit.new(1) stmt.key = 'id' sql = @visitor.accept(stmt) sql.must_be_like "UPDATE NULL WHERE 'id' IN (SELECT 'id' FETCH FIRST 1 ROWS ONLY)" end end end end arel-4.0.0/test/visitors/test_bind_visitor.rb0000644000004100000410000000277612161114331021413 0ustar www-datawww-datarequire 'helper' require 'arel/visitors/bind_visitor' require 'support/fake_record' module Arel module Visitors class TestBindVisitor < MiniTest::Unit::TestCase ## # 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) { "replace" } actual.must_be_like "\"name\" = replace" end def test_visitor_yields_on_binds visitor = Class.new(Arel::Visitors::Visitor) { def initialize omg end include Arel::Visitors::BindVisitor }.new nil bp = Nodes::BindParam.new 'omg' called = false visitor.accept(bp) { called = true } assert called end def test_visitor_only_yields_on_binds visitor = Class.new(Arel::Visitors::Visitor) { def initialize omg end include Arel::Visitors::BindVisitor }.new(nil) bp = Arel.sql 'omg' called = false assert_raises(TypeError) { visitor.accept(bp) { called = true } } refute called end end end end arel-4.0.0/test/visitors/test_mssql.rb0000644000004100000410000000524412161114331020050 0ustar www-datawww-datarequire 'helper' module Arel module Visitors describe 'the mssql visitor' do before do @visitor = MSSQL.new Table.engine.connection @table = Arel::Table.new "users" end it 'should not modify query if no offset or limit' do stmt = Nodes::SelectStatement.new sql = @visitor.accept(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 = @visitor.accept(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 = @visitor.accept(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 = @visitor.accept(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 = @visitor.accept(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 = @visitor.accept(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 = @visitor.accept(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 arel-4.0.0/test/visitors/test_mysql.rb0000644000004100000410000000331112161114331020047 0ustar www-datawww-datarequire 'helper' module Arel module Visitors describe 'the mysql visitor' do before do @visitor = MySQL.new Table.engine.connection end it 'squashes parenthesis on multiple unions' do subnode = Nodes::Union.new 'left', 'right' node = Nodes::Union.new subnode, 'topright' assert_equal 1, @visitor.accept(node).scan('(').length subnode = Nodes::Union.new 'left', 'right' node = Nodes::Union.new 'topleft', subnode assert_equal 1, @visitor.accept(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 = @visitor.accept(stmt) sql.must_be_like "SELECT FROM DUAL LIMIT 18446744073709551615 OFFSET 1" end it "should escape LIMIT" do sc = Arel::Nodes::UpdateStatement.new sc.limit = Nodes::Limit.new("omg") assert_equal("UPDATE NULL LIMIT 'omg'", @visitor.accept(sc)) end it 'uses DUAL for empty from' do stmt = Nodes::SelectStatement.new sql = @visitor.accept(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')) @visitor.accept(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')) @visitor.accept(node).must_be_like "LOCK IN SHARE MODE" end end end end end arel-4.0.0/test/visitors/test_sqlite.rb0000644000004100000410000000105212161114331020203 0ustar www-datawww-datarequire '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) sql.must_be_like "SELECT LIMIT -1 OFFSET 1" end it 'does not support locking' do node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) @visitor.accept(node).must_be_nil end end end end arel-4.0.0/test/visitors/test_dot.rb0000644000004100000410000000350712161114331017477 0ustar www-datawww-datarequire 'helper' module Arel module Visitors class TestDot < MiniTest::Unit::TestCase 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 end end def test_named_function func = Nodes::NamedFunction.new 'omg', 'omg' @visitor.accept func 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 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 end end end end end arel-4.0.0/test/visitors/test_to_sql.rb0000644000004100000410000003221012161114331020203 0ustar www-datawww-datarequire 'helper' module Arel module Visitors describe 'the to_sql visitor' do before do @visitor = ToSql.new Table.engine.connection @table = Table.new(:users) @attr = @table[:id] end it 'works with BindParams' do node = Nodes::BindParam.new 'omg' sql = @visitor.accept node sql.must_be_like 'omg' end it 'can define a dispatch method' do visited = false viz = Class.new(Arel::Visitors::Visitor) { define_method(:hello) do |node| visited = true end def dispatch { Arel::Table => 'hello' } end }.new viz.accept(@table) assert visited, 'hello method was called' end it 'should not quote sql literals' do node = @table[Arel.star] sql = @visitor.accept node sql.must_be_like '"users".*' end it 'should visit named functions' do function = Nodes::NamedFunction.new('omg', [Arel.star]) assert_equal 'omg(*)', @visitor.accept(function) end it 'should chain predications on named functions' do function = Nodes::NamedFunction.new('omg', [Arel.star]) sql = @visitor.accept(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(*)', @visitor.accept(function) function = Nodes::Sum.new([Arel.star]) assert_equal 'SUM(*)', @visitor.accept(function) function = Nodes::Max.new([Arel.star]) assert_equal 'MAX(*)', @visitor.accept(function) function = Nodes::Min.new([Arel.star]) assert_equal 'MIN(*)', @visitor.accept(function) function = Nodes::Avg.new([Arel.star]) assert_equal 'AVG(*)', @visitor.accept(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 *)', @visitor.accept(function) function = Nodes::Sum.new([Arel.star]) function.distinct = true assert_equal 'SUM(DISTINCT *)', @visitor.accept(function) function = Nodes::Max.new([Arel.star]) function.distinct = true assert_equal 'MAX(DISTINCT *)', @visitor.accept(function) function = Nodes::Min.new([Arel.star]) function.distinct = true assert_equal 'MIN(DISTINCT *)', @visitor.accept(function) function = Nodes::Avg.new([Arel.star]) function.distinct = true assert_equal 'AVG(DISTINCT *)', @visitor.accept(function) end it 'works with lists' do function = Nodes::NamedFunction.new('omg', [Arel.star, Arel.star]) assert_equal 'omg(*, *)', @visitor.accept(function) end describe 'equality' do it 'should handle false' do sql = @visitor.accept Nodes::Equality.new(false, false) sql.must_be_like %{ 'f' = 'f' } end it 'should use the column to quote' do table = Table.new(:users) sql = @visitor.accept Nodes::Equality.new(table[:id], '1-fooo') sql.must_be_like %{ "users"."id" = 1 } end end it "should visit string subclass" do @visitor.accept(Class.new(String).new(":'(")) @visitor.accept(Class.new(Class.new(String)).new(":'(")) end it "should visit_Class" do @visitor.accept(DateTime).must_equal "'DateTime'" end it "should escape LIMIT" do sc = Arel::Nodes::SelectStatement.new sc.limit = Arel::Nodes::Limit.new("omg") assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) end it "should visit_DateTime" do @visitor.accept DateTime.now end it "should visit_Float" do @visitor.accept 2.14 end it "should visit_Not" do sql = @visitor.accept 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 = @visitor.accept 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 = @visitor.accept as sql.must_be_like "foo AS bar" end it "should visit_Bignum" do @visitor.accept 8787878092 end it "should visit_Hash" do @visitor.accept({:a => 1}) end it "should visit_BigDecimal" do @visitor.accept BigDecimal.new('2.14') end it "should visit_Date" do @visitor.accept Date.today end it "should visit_NilClass" do @visitor.accept(nil).must_be_like "NULL" end it "should visit_Arel_SelectManager, which is a subquery" do mgr = Table.new(:foo).project(:bar) @visitor.accept(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)] @visitor.accept(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) @visitor.accept(node).must_be_like %{ "users"."id" = 10 OR "users"."id" = 11 } end it "should visit visit_Arel_Attributes_Time" do attr = Attributes::Time.new(@attr.relation, @attr.name) @visitor.accept attr end it "should visit_TrueClass" do test = Table.new(:users)[:bool].eq(true) @visitor.accept(test).must_be_like %{ "users"."bool" = 't' } end describe "Nodes::Ordering" do it "should know how to visit" do node = @attr.desc @visitor.accept(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] @visitor.accept(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 [] @visitor.accept(node).must_equal '1=0' end it 'can handle two dot ranges' do node = @attr.in 1..3 @visitor.accept(node).must_be_like %{ "users"."id" BETWEEN 1 AND 3 } end it 'can handle three dot ranges' do node = @attr.in 1...3 @visitor.accept(node).must_be_like %{ "users"."id" >= 1 AND "users"."id" < 3 } end it 'can handle ranges bounded by infinity' do node = @attr.in 1..Float::INFINITY @visitor.accept(node).must_be_like %{ "users"."id" >= 1 } node = @attr.in(-Float::INFINITY..3) @visitor.accept(node).must_be_like %{ "users"."id" <= 3 } node = @attr.in(-Float::INFINITY...3) @visitor.accept(node).must_be_like %{ "users"."id" < 3 } node = @attr.in(-Float::INFINITY..Float::INFINITY) @visitor.accept(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 @visitor.accept(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 in_node = Nodes::In.new @attr, %w{ a b c } visitor = visitor.new(Table.engine.connection) visitor.expected = Table.engine.connection.columns(:users).find { |x| x.name == 'name' } visitor.accept(in_node).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) @visitor.accept(node).must_equal %("products"."price" * "currency_rates"."rate") end it "should handle Division" do node = Arel::Attributes::Decimal.new(Table.new(:products), :price) / 5 @visitor.accept(node).must_equal %("products"."price" / 5) end it "should handle Addition" do node = Arel::Attributes::Decimal.new(Table.new(:products), :price) + 6 @visitor.accept(node).must_equal %(("products"."price" + 6)) end it "should handle Subtraction" do node = Arel::Attributes::Decimal.new(Table.new(:products), :price) - 7 @visitor.accept(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) ) @visitor.accept(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] @visitor.accept(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 [] @visitor.accept(node).must_equal '1=1' end it 'can handle two dot ranges' do node = @attr.not_in 1..3 @visitor.accept(node).must_be_like %{ "users"."id" < 1 OR "users"."id" > 3 } end it 'can handle three dot ranges' do node = @attr.not_in 1...3 @visitor.accept(node).must_be_like %{ "users"."id" < 1 OR "users"."id" >= 3 } end it 'can handle ranges bounded by infinity' do node = @attr.not_in 1..Float::INFINITY @visitor.accept(node).must_be_like %{ "users"."id" < 1 } node = @attr.not_in(-Float::INFINITY..3) @visitor.accept(node).must_be_like %{ "users"."id" > 3 } node = @attr.not_in(-Float::INFINITY...3) @visitor.accept(node).must_be_like %{ "users"."id" >= 3 } node = @attr.not_in(-Float::INFINITY..Float::INFINITY) @visitor.accept(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 @visitor.accept(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 in_node = Nodes::NotIn.new @attr, %w{ a b c } visitor = visitor.new(Table.engine.connection) visitor.expected = Table.engine.connection.columns(:users).find { |x| x.name == 'name' } visitor.accept(in_node).must_equal %("users"."name" NOT IN ('a', 'b', 'c')) end end describe 'Equality' do it "should escape strings" do test = Table.new(:users)[:name].eq 'Aaron Patterson' @visitor.accept(test).must_be_like %{ "users"."name" = 'Aaron Patterson' } end end describe 'Constants' do it "should handle true" do test = Table.new(:users).create_true @visitor.accept(test).must_be_like %{ TRUE } end it "should handle false" do test = Table.new(:users).create_false @visitor.accept(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' @visitor.accept(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 @visitor.accept(core) end end end end end end arel-4.0.0/test/visitors/test_depth_first.rb0000644000004100000410000001412012161114331021215 0ustar www-datawww-datarequire 'helper' module Arel module Visitors class TestDepthFirst < MiniTest::Unit::TestCase 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_outer_join join = Nodes::OuterJoin.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_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 arel-4.0.0/test/visitors/test_oracle.rb0000644000004100000410000001244512161114331020157 0ustar www-datawww-datarequire 'helper' module Arel module Visitors describe 'the oracle visitor' do before do @visitor = Oracle.new Table.engine.connection_pool 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 = @visitor.accept(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 = @visitor.accept(stmt) sql2 = @visitor.accept(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 = @visitor.accept(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 = @visitor.accept(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 = @visitor.accept 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 = @visitor.accept stmt sql2 = @visitor.accept 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 = @visitor.accept stmt sql.must_be_like %{ SELECT * FROM (SELECT ORDER BY foo) WHERE ROWNUM <= 10 } end it 'creates a subquery when there is DISTINCT' do stmt = Nodes::SelectStatement.new stmt.cores.first.projections << Nodes::SqlLiteral.new('DISTINCT id') stmt.limit = Arel::Nodes::Limit.new(10) sql = @visitor.accept 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 = @visitor.accept 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 = @visitor.accept stmt sql2 = @visitor.accept 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 = @visitor.accept 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 = @visitor.accept 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')) @visitor.accept(node).must_be_like "FOR UPDATE" end end end end end arel-4.0.0/test/test_delete_manager.rb0000644000004100000410000000200412161114331017752 0ustar www-datawww-datarequire '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 arel-4.0.0/test/test_crud.rb0000644000004100000410000000261112161114331015757 0ustar www-datawww-datarequire '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']] 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 arel-4.0.0/test/attributes/0000755000004100000410000000000012161114331015624 5ustar www-datawww-dataarel-4.0.0/test/attributes/test_attribute.rb0000644000004100000410000005275612161114331021232 0ustar www-datawww-datarequire '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 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 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 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 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 # FIXME: backwards compat. Is this really necessary? it 'should set the alias to "avg_id"' do relation = Table.new(:users) mgr = relation.project relation[:id].average mgr.to_sql.must_be_like %{ SELECT AVG("users"."id") AS avg_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 # FIXME: backwards compat. Is this really necessary? it 'should set the alias to "max_id"' do relation = Table.new(:users) mgr = relation.project relation[:id].maximum mgr.to_sql.must_be_like %{ SELECT MAX("users"."id") AS max_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 # FIXME: backwards compat. Is this really necessary? it 'should set the alias to "sum_id"' do relation = Table.new(:users) mgr = relation.project relation[:id].sum mgr.to_sql.must_be_like %{ SELECT SUM("users"."id") AS sum_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.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 '#in' do it 'can be constructed with a list' do end it 'should return an in node' do attribute = Attribute.new nil, nil node = Nodes::In.new attribute, [1,2,3] node.left.must_equal attribute node.right.must_equal [1, 2, 3] 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 '#not_in' do it 'can be constructed with a list' do end it 'should return a NotIn node' do attribute = Attribute.new nil, nil node = Nodes::NotIn.new attribute, [1,2,3] node.left.must_equal attribute node.right.must_equal [1, 2, 3] 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 arel-4.0.0/test/test_select_manager.rb0000644000004100000410000010652612161114331020005 0ustar www-datawww-datarequire 'helper' module Arel class EngineProxy attr_reader :executed attr_reader :connection_pool attr_reader :spec attr_reader :config def initialize engine @engine = engine @executed = [] @connection_pool = self @spec = self @config = { :adapter => 'sqlite3' } end def with_connection yield self end def connection self end def quote_table_name thing; @engine.connection.quote_table_name thing end def quote_column_name thing; @engine.connection.quote_column_name thing end def quote thing, column; @engine.connection.quote thing, column end def columns table, message = nil @engine.connection.columns table, message end def columns_hash @engine.connection.columns_hash end def table_exists? name @engine.connection.table_exists? name end def tables @engine.connection.tables end def visitor @engine.connection.visitor end def execute sql, name = nil, *args @executed << sql end alias :update :execute alias :delete :execute alias :insert :execute end describe 'select manager' do def test_join_sources manager = Arel::SelectManager.new Table.engine manager.join_sources << Arel::Nodes::StringJoin.new('foo') assert_equal "SELECT FROM 'foo'", manager.to_sql 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 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' 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, :engine => Table.engine, :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, :engine => Table.engine, :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, :engine => Table.engine, :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 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 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].in(18..60)) @m2 = Arel::SelectManager.new Table.engine, table @m2.project Arel.star @m2.where(table[:age].in(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 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 ast = mgr.ast mgr.visitor.accept(ast).must_equal mgr.to_sql 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 'insert' do it 'uses the select FROM' do engine = EngineProxy.new Table.engine table = Table.new :users manager = Arel::SelectManager.new engine manager.from table manager.insert 'VALUES(NULL)' engine.executed.last.must_be_like %{ INSERT INTO "users" VALUES(NULL) } 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 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 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 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 it 'has order attributes for expressions' do table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.project SqlLiteral.new '*' manager.from table manager.order table[:id].count.desc manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY COUNT("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 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 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 'noops on nil' do manager = Arel::SelectManager.new Table.engine manager.join(nil).must_equal manager end end describe 'joins' do it 'returns 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])) manager.join_sql.must_be_like %{ INNER JOIN "users" "users_2" "users"."id" = "users_2"."id" } 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])) manager.join_sql.must_be_like %{ LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" } 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 'returns string join sql' do manager = Arel::SelectManager.new Table.engine manager.from Nodes::StringJoin.new('hello') manager.join_sql.must_be_like %{ 'hello' } end it 'returns nil join sql' do manager = Arel::SelectManager.new Table.engine manager.join_sql.must_be_nil end end describe 'order_clauses' do it 'returns order clauses as a list' do table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.from table manager.order table[:id] manager.order_clauses.first.must_be_like %{ "users"."id" } 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 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 engine = EngineProxy.new Table.engine table = Table.new :users manager = Arel::SelectManager.new engine manager.from table stmt = manager.compile_delete stmt.to_sql.must_be_like %{ DELETE FROM "users" } end it "copies where" do engine = EngineProxy.new Table.engine table = Table.new :users manager = Arel::SelectManager.new 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 'copies limits' do engine = EngineProxy.new Table.engine table = Table.new :users manager = Arel::SelectManager.new engine manager.from table manager.take 1 stmt = manager.compile_update(SqlLiteral.new('foo = bar')) 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 engine = EngineProxy.new Table.engine table = Table.new :users manager = Arel::SelectManager.new engine manager.from table manager.order :foo stmt = manager.compile_update(SqlLiteral.new('foo = bar')) 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 'takes a string' do engine = EngineProxy.new Table.engine table = Table.new :users manager = Arel::SelectManager.new engine manager.from table stmt = manager.compile_update(SqlLiteral.new('foo = bar')) stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } end it 'copies where clauses' do engine = EngineProxy.new Table.engine table = Table.new :users manager = Arel::SelectManager.new engine manager.where table[:id].eq 10 manager.from table stmt = manager.compile_update(table[:id] => 1) 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 engine = EngineProxy.new Table.engine table = Table.new :users manager = Arel::SelectManager.new engine manager.where table[:foo].eq 10 manager.take 42 manager.from table stmt = manager.compile_update(table[:id] => 1) 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 it 'executes an update statement' do engine = EngineProxy.new Table.engine table = Table.new :users manager = Arel::SelectManager.new engine manager.from table stmt = manager.compile_update(table[:id] => 1) stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 } end end describe 'project' do 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 Nodes::SqlLiteral.new('*') manager.to_sql.must_be_like %{ SELECT * } end it "takes sql literals" do manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new '*' 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 "join" do 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 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 end end end arel-4.0.0/test/test_update_manager.rb0000644000004100000410000000637412161114331020010 0ustar www-datawww-datarequire '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.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 arel-4.0.0/test/test_table.rb0000644000004100000410000001325512161114331016117 0ustar www-datawww-datarequire '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::OuterJoin assert_kind_of Arel::Nodes::OuterJoin, 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 assert_equal 'INSERT INTO NULL 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 '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 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 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 SqlLiteral.new '*' manager.to_sql.must_be_like %{ SELECT * FROM "users" } end it 'takes multiple parameters' do manager = @relation.project SqlLiteral.new('*'), 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 arel-4.0.0/test/test_activerecord_compat.rb0000644000004100000410000000073312161114331021042 0ustar www-datawww-datarequire 'helper' module Arel describe 'activerecord compatibility' do describe 'select manager' do it 'provides wheres' do table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.where table[:id].eq 1 manager.where table[:name].eq 'Aaron' manager.wheres.map { |x| x.value }.join(', ').must_equal "\"users\".\"id\" = 1, \"users\".\"name\" = 'Aaron'" end end end end arel-4.0.0/test/test_insert_manager.rb0000644000004100000410000000764712161114331020036 0ustar www-datawww-datarequire '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.values = manager.create_values [Arel.sql('*')], %w{ a } manager.to_sql.must_be_like %{ INSERT INTO NULL 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 'takes an empty list' do manager = Arel::InsertManager.new Table.engine manager.insert [] end end describe 'into' do it 'takes an engine' 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 "puts shit together" 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 end end arel-4.0.0/test/support/0000755000004100000410000000000012161114331015152 5ustar www-datawww-dataarel-4.0.0/test/support/fake_record.rb0000644000004100000410000000447212161114331017752 0ustar www-datawww-datamodule 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 && column.type == :integer return 'NULL' if thing.nil? return thing.to_i end case thing when true "'t'" when false "'f'" when nil 'NULL' when Numeric thing else "'#{thing}'" 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 end class Base attr_accessor :connection_pool def initialize @connection_pool = ConnectionPool.new end def connection connection_pool.connection end end end arel-4.0.0/Rakefile0000644000004100000410000000113512161114331014124 0ustar www-datawww-datarequire "rubygems" gem 'hoe', '>= 3.3.1' require 'hoe' Hoe.plugins.delete :rubyforge Hoe.plugin :minitest Hoe.plugin :gemspec # `gem install hoe-gemspec` Hoe.plugin :git # `gem install hoe-git` Hoe.plugin :bundler # `gem install hoe-bundler` Hoe.spec 'arel' do developer('Aaron Patterson', 'aaron@tenderlovemaking.com') developer('Bryan Halmkamp', 'bryan@brynary.com') developer('Emilio Tagua', 'miloops@gmail.com') developer('Nick Kallen', 'nick@example.org') # FIXME: need Nick's email self.readme_file = 'README.markdown' self.extra_rdoc_files = FileList['README.markdown'] end arel-4.0.0/History.txt0000644000004100000410000001224012161114331014660 0ustar www-datawww-data== 2.2.1 / 2011-09-15 * Enhancements * Added UpdateManager#key to access the key value * Added SelectManager#projections= to override any existing projections * Added SelectManager#source to get the source of the last select core in the AST == 2.2.0 / 2011-08-09 * Bug Fixes * The database connection caches visitors for generating SQL. * FALSE and TRUE nodes can be constructed. * Fixed ORDER BY / LIMIT clauses for UPDATE statements in Oracle. == 2.1.4 / 2011-07-25 * Bug Fixes * Fix depth-first traversal to understand ascending / descending nodes. * Parentheis are suppressed with nested unions in MySQL. Thanks jhtwong! == 2.1.3 / 2011-06-27 * Bug Fixues * Fixed broken gem build. == 2.1.2 / 2011-06-27 * Bug Fixes * Visitors can define their own cache strategey so caches are not shared. Fixes #57 * Informix support fixed. Thanks Khronos. * Ordering nodes broken to subclasses. Thanks Ernie Miller! * Reversal supported in ordering nodes. Thanks Ernie Miller! == 2.1.1 / 2011/05/14 * Bug fixes * Fixed thread safety bug in ToSql visitor. Thanks Damon McCormick and Cameron Walters! == 2.1.0 / 2011/04/30 * Enhancements * AST is now Enumerable * AND nodes are now n-ary nodes * SQL Literals may be used as Attribute names * Added Arel::Nodes::NamedFunction for representing generic SQL functions * Add Arel::SelectManager#limit= * Add Arel::SelectManager#offset * Add Arel::SelectManager#offset= * Added Arel::SelectManager#create_insert for building an insert manager. * SQL Literals are allowed for values in INSERT statements. * Math operations have been added to attributes, thanks to Vladimir Meremyanin. * Bug fixes * MSSQL adds TOP to sub selects * Assigning nil to take() removes LIMIT from statement. * Assigning nil to offset() removes OFFSET from statement. * TableAlias leg ordering fixed * Deprecations * Calls to `insert` are deprecated. Please use `compile_insert` then call `to_sql` on the resulting object and execute that SQL. * Calls to `update` are deprecated. Please use `compile_update` then call `to_sql` on the resulting object and execute that SQL. * Calls to `delete` are deprecated. Please use `compile_delete` then call `to_sql` on the resulting object and execute that SQL. * Arel::Table#joins is deprecated and will be removed in 3.0.0 with no replacement. * Arel::Table#columns is deprecated and will be removed in 3.0.0 with no replacement. * Arel::Table.table_cache is deprecated and will be removed in 3.0.0 with no replacement. * Arel::Nodes::And.new takes a single list instead of left and right. * Arel::Table#primary_key is deprecated and will be removed in 3.0.0 with no replacement. * Arel::SelectManager#where_clauses is deprecated and will be removed in 3.0.0 with no replacement. * Arel::SelectManager#wheres is deprecated and will be removed in 3.0.0 with no replacement. == 2.0.9 / 2010/02/25 * Bug Fixes * Custom LOCK strings are allowed. Fixes LH # 6399 https://rails.lighthouseapp.com/projects/8994/tickets/6399-allow-database-specific-locking-clauses-to-be-used * Strings passed to StringManager#on will be automatically tagged as SQL literals. Fixes Rails LH #6384 https://rails.lighthouseapp.com/projects/8994/tickets/6384-activerecord-303-and-3-0-stable-generate-invalid-sql-for-has_many-through-association-with-conditions == 2.0.8 / 2010/02/08 * Bug Fixes * Added set operation support * Fixed problems with *_any / *_all methods. == 2.0.7 * Bug Fixes * Limit members are visited * Fixing MSSQL TOP support == 2.0.6 12/01/2010 * Bug Fixes * Rails 3.0.x does not like that Node is Enumerable, so removing for now. == 2.0.5 11/30/2010 * Enhancements * Arel::Visitors::DepthFirst can walk your AST depth first * Arel::Nodes::Node is enumerable, depth first * Bug fixes * #lock will lock SELECT statements "FOR UPDATE" on mysql * Nodes::Node#not factory method added for creating Nodes::Not nodes * Added an As node * Deprecations * Support for Subclasses of core classes will be removed in Arel version 2.2.0 == 2.0.4 * Bug fixes * Speed improvements for Range queries. Thanks Rolf Timmermans! == 2.0.3 * Bug fixes * Fixing Oracle support * Added a visitor for "Class" objects == 2.0.2 * Bug fixes * MySQL selects from DUAL on empty FROM * Visitor translates nil to NULL * Visitor translates Bignum properly == 2.0.1 * Bug fixes == 2.0.0 / 2010-08-01 * Enhancements * Recreate library using the Visitor pattern. http://en.wikipedia.org/wiki/Visitor_pattern == 0.3.0 / 2010-03-10 * Enhancements * Introduced "SQL compilers" for query generation. * Added support for Oracle (Raimonds Simanovskis) and IBM/DB (Praveen Devarao). * Improvements to give better support to Active Record. == 0.2.1 / 2010-02-05 * Enhancements * Bump dependency version of activesupport to 3.0.0.beta == 0.2.0 / 2010-01-31 * Ruby 1.9 compatibility * Many improvements to support the Arel integration into Active Record (see `git log v0.1.0..v0.2.0`) * Thanks to Emilio Tagua and Pratik Naik for many significant contributions! == 0.1.0 / 2009-08-06 * 1 major enhancement * Birthday! arel-4.0.0/.gemtest0000644000004100000410000000000012161114331014116 0ustar www-datawww-dataarel-4.0.0/README.markdown0000644000004100000410000001133512161114331015163 0ustar www-datawww-data# Arel [![Build Status](https://secure.travis-ci.org/rails/arel.png)](http://travis-ci.org/rails/arel) [![Dependency Status](https://gemnasium.com/rails/arel.png)](https://gemnasium.com/rails/arel) * http://github.com/rails/arel ## DESCRIPTION Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation of complex SQL queries 2. Adapts to various RDBMS systems 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. ## Status For the moment, Arel uses Active Record's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion. ## A Gentle Introduction Generating a query with Arel is simple. For example, in order to produce SELECT * FROM users you construct a table relation and convert it to sql: users = Arel::Table.new(:users) query = users.project(Arel.sql('*')) query.to_sql ### More Sophisticated Queries Here is a whirlwind tour through the most common relational operators. These will probably cover 80% of all interaction with the database. First is the 'restriction' operator, `where`: users.where(users[:name].eq('amy')) # => SELECT * FROM users WHERE users.name = 'amy' What would, in SQL, be part of the `SELECT` clause is called in Arel a `projection`: users.project(users[:id]) # => SELECT users.id FROM users Joins resemble SQL strongly: users.join(photos).on(users[:id].eq(photos[:user_id])) # => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id What are called `LIMIT` and `OFFSET` in SQL are called `take` and `skip` in Arel: users.take(5) # => SELECT * FROM users LIMIT 5 users.skip(4) # => SELECT * FROM users OFFSET 4 `GROUP BY` is called `group`: users.project(users[:name]).group(users[:name]) # => SELECT users.name FROM users GROUP BY users.name The best property of the Relational Algebra is its "composability", or closure under all operations. For example, to restrict AND project, just "chain" the method invocations: users \ .where(users[:name].eq('amy')) \ .project(users[:id]) \ # => SELECT users.id FROM users WHERE users.name = 'amy' All operators are chainable in this way, and they are chainable any number of times, in any order. users.where(users[:name].eq('bob')).where(users[:age].lt(25)) Of course, many of the operators take multiple arguments, so the last example can be written more tersely: users.where(users[:name].eq('bob'), users[:age].lt(25)) The `OR` operator works like this: users.where(users[:name].eq('bob').or(users[:age].lt(25))) The `AND` operator behaves similarly. ### The Crazy Features The examples above are fairly simple and other libraries match or come close to matching the expressiveness of Arel (e.g., `Sequel` in Ruby). #### Inline math operations Suppose we have a table `products` with prices in different currencies. And we have a table `currency_rates`, of constantly changing currency rates. In Arel: products = Arel::Table.new(:products) products.columns # => [products[:id], products[:name], products[:price], products[:currency_id]] currency_rates = Arel::Table.new(:currency_rates) currency_rates.columns # => [currency_rates[:from_id], currency_rates[:to_id], currency_rates[:date], currency_rates[:rate]] Now, to order products by price in user preferred currency simply call: products. join(:currency_rates).on(products[:currency_id].eq(currency_rates[:from_id])). where(currency_rates[:to_id].eq(user_preferred_currency), currency_rates[:date].eq(Date.today)). order(products[:price] * currency_rates[:rate]) #### Complex Joins Where Arel really shines in its ability to handle complex joins and aggregations. As a first example, let's consider an "adjacency list", a tree represented in a table. Suppose we have a table `comments`, representing a threaded discussion: comments = Arel::Table.new(:comments) And this table has the following attributes: comments.columns # => [comments[:id], comments[:body], comments[:parent_id]] The `parent_id` column is a foreign key from the `comments` table to itself. Now, joining a table to itself requires aliasing in SQL. In fact, you may alias in Arel as well: replies = comments.alias comments_with_replies = \ comments.join(replies).on(replies[:parent_id].eq(comments[:id])) # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id This will return the first comment's reply's body. ### License Arel is released under the [MIT License](http://opensource.org/licenses/MIT). arel-4.0.0/arel.gemspec0000644000004100000410000001607412161114331014757 0ustar www-datawww-data# -*- encoding: utf-8 -*- Gem::Specification.new do |s| s.name = "arel" s.version = "4.0.0.20130418133826" s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] s.date = "2013-04-18" s.description = "Arel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMS systems\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"] s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/deprecated.rb", "lib/arel/expression.rb", "lib/arel/expressions.rb", "lib/arel/factory_methods.rb", "lib/arel/insert_manager.rb", "lib/arel/math.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/ascending.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/descending.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/extract.rb", "lib/arel/nodes/false.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/infix_operation.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/over.rb", "lib/arel/nodes/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/sql/engine.rb", "lib/arel/sql_literal.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.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/join_sql.rb", "lib/arel/visitors/mssql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/order_clauses.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/sqlite.rb", "lib/arel/visitors/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "lib/arel/window_predications.rb", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/support/fake_record.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] s.homepage = "http://github.com/rails/arel" s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = "arel" s.rubygems_version = "2.0.2" s.summary = "Arel is a SQL AST manager for Ruby" s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, ["~> 4.6"]) s.add_development_dependency(%q, ["~> 3.10"]) s.add_development_dependency(%q, ["~> 3.5"]) else s.add_dependency(%q, ["~> 4.6"]) s.add_dependency(%q, ["~> 3.10"]) s.add_dependency(%q, ["~> 3.5"]) end else s.add_dependency(%q, ["~> 4.6"]) s.add_dependency(%q, ["~> 3.10"]) s.add_dependency(%q, ["~> 3.5"]) end end arel-4.0.0/MIT-LICENSE.txt0000644000004100000410000000212312161114331014727 0ustar www-datawww-dataCopyright (c) 2007-2010 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. arel-4.0.0/metadata.yml0000644000004100000410000001733112161114331014767 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: arel version: !ruby/object:Gem::Version version: 4.0.0 prerelease: platform: ruby authors: - Aaron Patterson - Bryan Halmkamp - Emilio Tagua - Nick Kallen autorequire: bindir: bin cert_chain: [] date: 2013-04-18 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: minitest requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '4.4' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '4.4' - !ruby/object:Gem::Dependency name: rdoc requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '4.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '4.0' - !ruby/object:Gem::Dependency name: hoe requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '3.5' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '3.5' description: ! 'Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation of complex SQL queries 2. Adapts to various RDBMS systems 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 - nick@example.org executables: [] extensions: [] extra_rdoc_files: - History.txt - MIT-LICENSE.txt - Manifest.txt - README.markdown files: - .autotest - .gemtest - .travis.yml - Gemfile - History.txt - MIT-LICENSE.txt - Manifest.txt - README.markdown - Rakefile - arel.gemspec - lib/arel.rb - lib/arel/alias_predication.rb - lib/arel/attributes.rb - lib/arel/attributes/attribute.rb - lib/arel/compatibility/wheres.rb - lib/arel/crud.rb - lib/arel/delete_manager.rb - lib/arel/deprecated.rb - lib/arel/expression.rb - lib/arel/expressions.rb - lib/arel/factory_methods.rb - lib/arel/insert_manager.rb - lib/arel/math.rb - lib/arel/nodes.rb - lib/arel/nodes/and.rb - lib/arel/nodes/ascending.rb - lib/arel/nodes/binary.rb - lib/arel/nodes/count.rb - lib/arel/nodes/delete_statement.rb - lib/arel/nodes/descending.rb - lib/arel/nodes/equality.rb - lib/arel/nodes/extract.rb - lib/arel/nodes/false.rb - lib/arel/nodes/function.rb - lib/arel/nodes/grouping.rb - lib/arel/nodes/in.rb - lib/arel/nodes/infix_operation.rb - lib/arel/nodes/inner_join.rb - lib/arel/nodes/insert_statement.rb - lib/arel/nodes/join_source.rb - lib/arel/nodes/named_function.rb - lib/arel/nodes/node.rb - lib/arel/nodes/outer_join.rb - lib/arel/nodes/over.rb - lib/arel/nodes/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/sql/engine.rb - lib/arel/sql_literal.rb - lib/arel/table.rb - lib/arel/tree_manager.rb - lib/arel/update_manager.rb - lib/arel/visitors.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/join_sql.rb - lib/arel/visitors/mssql.rb - lib/arel/visitors/mysql.rb - lib/arel/visitors/oracle.rb - lib/arel/visitors/order_clauses.rb - lib/arel/visitors/postgresql.rb - lib/arel/visitors/sqlite.rb - lib/arel/visitors/to_sql.rb - lib/arel/visitors/visitor.rb - lib/arel/visitors/where_sql.rb - lib/arel/window_predications.rb - test/attributes/test_attribute.rb - test/helper.rb - test/nodes/test_and.rb - test/nodes/test_as.rb - test/nodes/test_ascending.rb - test/nodes/test_bin.rb - test/nodes/test_count.rb - test/nodes/test_delete_statement.rb - test/nodes/test_descending.rb - test/nodes/test_distinct.rb - test/nodes/test_equality.rb - test/nodes/test_extract.rb - test/nodes/test_false.rb - test/nodes/test_grouping.rb - test/nodes/test_infix_operation.rb - test/nodes/test_insert_statement.rb - test/nodes/test_named_function.rb - test/nodes/test_node.rb - test/nodes/test_not.rb - test/nodes/test_or.rb - test/nodes/test_over.rb - test/nodes/test_select_core.rb - test/nodes/test_select_statement.rb - test/nodes/test_sql_literal.rb - test/nodes/test_sum.rb - test/nodes/test_table_alias.rb - test/nodes/test_true.rb - test/nodes/test_update_statement.rb - test/nodes/test_window.rb - test/support/fake_record.rb - test/test_activerecord_compat.rb - test/test_attributes.rb - test/test_crud.rb - test/test_delete_manager.rb - test/test_factory_methods.rb - test/test_insert_manager.rb - test/test_select_manager.rb - test/test_table.rb - test/test_update_manager.rb - test/visitors/test_bind_visitor.rb - test/visitors/test_depth_first.rb - test/visitors/test_dot.rb - test/visitors/test_ibm_db.rb - test/visitors/test_informix.rb - test/visitors/test_join_sql.rb - test/visitors/test_mssql.rb - test/visitors/test_mysql.rb - test/visitors/test_oracle.rb - test/visitors/test_postgres.rb - test/visitors/test_sqlite.rb - test/visitors/test_to_sql.rb homepage: http://github.com/rails/arel licenses: [] post_install_message: rdoc_options: - --main - README.markdown require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: arel rubygems_version: 1.8.23 signing_key: specification_version: 3 summary: Arel is a SQL AST manager for Ruby test_files: - test/attributes/test_attribute.rb - test/nodes/test_and.rb - test/nodes/test_as.rb - test/nodes/test_ascending.rb - test/nodes/test_bin.rb - test/nodes/test_count.rb - test/nodes/test_delete_statement.rb - test/nodes/test_descending.rb - test/nodes/test_distinct.rb - test/nodes/test_equality.rb - test/nodes/test_extract.rb - test/nodes/test_false.rb - test/nodes/test_grouping.rb - test/nodes/test_infix_operation.rb - test/nodes/test_insert_statement.rb - test/nodes/test_named_function.rb - test/nodes/test_node.rb - test/nodes/test_not.rb - test/nodes/test_or.rb - test/nodes/test_over.rb - test/nodes/test_select_core.rb - test/nodes/test_select_statement.rb - test/nodes/test_sql_literal.rb - test/nodes/test_sum.rb - test/nodes/test_table_alias.rb - test/nodes/test_true.rb - test/nodes/test_update_statement.rb - test/nodes/test_window.rb - test/test_activerecord_compat.rb - test/test_attributes.rb - test/test_crud.rb - test/test_delete_manager.rb - test/test_factory_methods.rb - test/test_insert_manager.rb - test/test_select_manager.rb - test/test_table.rb - test/test_update_manager.rb - test/visitors/test_bind_visitor.rb - test/visitors/test_depth_first.rb - test/visitors/test_dot.rb - test/visitors/test_ibm_db.rb - test/visitors/test_informix.rb - test/visitors/test_join_sql.rb - test/visitors/test_mssql.rb - test/visitors/test_mysql.rb - test/visitors/test_oracle.rb - test/visitors/test_postgres.rb - test/visitors/test_sqlite.rb - test/visitors/test_to_sql.rb arel-4.0.0/Gemfile0000644000004100000410000000047112161114331013754 0ustar www-datawww-data# -*- ruby -*- # DO NOT EDIT THIS FILE. Instead, edit Rakefile, and run `rake bundler:gemfile`. source "https://rubygems.org/" gem "minitest", "~>4.4", :group => [:development, :test] gem "rdoc", "~>4.0", :group => [:development, :test] gem "hoe", "~>3.5", :group => [:development, :test] # vim: syntax=ruby arel-4.0.0/Manifest.txt0000644000004100000410000000666412161114331015002 0ustar www-datawww-data.autotest .gemtest .travis.yml Gemfile History.txt MIT-LICENSE.txt Manifest.txt README.markdown Rakefile arel.gemspec lib/arel.rb lib/arel/alias_predication.rb lib/arel/attributes.rb lib/arel/attributes/attribute.rb lib/arel/compatibility/wheres.rb lib/arel/crud.rb lib/arel/delete_manager.rb lib/arel/deprecated.rb lib/arel/expression.rb lib/arel/expressions.rb lib/arel/factory_methods.rb lib/arel/insert_manager.rb lib/arel/math.rb lib/arel/nodes.rb lib/arel/nodes/and.rb lib/arel/nodes/ascending.rb lib/arel/nodes/binary.rb lib/arel/nodes/count.rb lib/arel/nodes/delete_statement.rb lib/arel/nodes/descending.rb lib/arel/nodes/equality.rb lib/arel/nodes/extract.rb lib/arel/nodes/false.rb lib/arel/nodes/function.rb lib/arel/nodes/grouping.rb lib/arel/nodes/in.rb lib/arel/nodes/infix_operation.rb lib/arel/nodes/inner_join.rb lib/arel/nodes/insert_statement.rb lib/arel/nodes/join_source.rb lib/arel/nodes/named_function.rb lib/arel/nodes/node.rb lib/arel/nodes/outer_join.rb lib/arel/nodes/over.rb lib/arel/nodes/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/sql/engine.rb lib/arel/sql_literal.rb lib/arel/table.rb lib/arel/tree_manager.rb lib/arel/update_manager.rb lib/arel/visitors.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/join_sql.rb lib/arel/visitors/mssql.rb lib/arel/visitors/mysql.rb lib/arel/visitors/oracle.rb lib/arel/visitors/order_clauses.rb lib/arel/visitors/postgresql.rb lib/arel/visitors/sqlite.rb lib/arel/visitors/to_sql.rb lib/arel/visitors/visitor.rb lib/arel/visitors/where_sql.rb lib/arel/window_predications.rb test/attributes/test_attribute.rb test/helper.rb test/nodes/test_and.rb test/nodes/test_as.rb test/nodes/test_ascending.rb test/nodes/test_bin.rb test/nodes/test_count.rb test/nodes/test_delete_statement.rb test/nodes/test_descending.rb test/nodes/test_distinct.rb test/nodes/test_equality.rb test/nodes/test_extract.rb test/nodes/test_false.rb test/nodes/test_grouping.rb test/nodes/test_infix_operation.rb test/nodes/test_insert_statement.rb test/nodes/test_named_function.rb test/nodes/test_node.rb test/nodes/test_not.rb test/nodes/test_or.rb test/nodes/test_over.rb test/nodes/test_select_core.rb test/nodes/test_select_statement.rb test/nodes/test_sql_literal.rb test/nodes/test_sum.rb test/nodes/test_table_alias.rb test/nodes/test_true.rb test/nodes/test_update_statement.rb test/nodes/test_window.rb test/support/fake_record.rb test/test_activerecord_compat.rb test/test_attributes.rb test/test_crud.rb test/test_delete_manager.rb test/test_factory_methods.rb test/test_insert_manager.rb test/test_select_manager.rb test/test_table.rb test/test_update_manager.rb test/visitors/test_bind_visitor.rb test/visitors/test_depth_first.rb test/visitors/test_dot.rb test/visitors/test_ibm_db.rb test/visitors/test_informix.rb test/visitors/test_join_sql.rb test/visitors/test_mssql.rb test/visitors/test_mysql.rb test/visitors/test_oracle.rb test/visitors/test_postgres.rb test/visitors/test_sqlite.rb test/visitors/test_to_sql.rb arel-4.0.0/.autotest0000644000004100000410000000100112161114331014320 0ustar www-datawww-data# -*- ruby -*- # require 'autotest/restart' ENV['GEM_PATH'] = "tmp/isolate/ruby-1.8" module Autotest::Restart Autotest.add_hook :updated do |at, *args| if args.flatten.include? ".autotest" then warn "Detected change to .autotest, restarting" cmd = %w(autotest) cmd << " -v" if $v cmd += ARGV exec(*cmd) end end end Autotest.add_hook :initialize do |at| at.add_exception 'tmp' at.testlib = "minitest/autorun" at.find_directories = ARGV unless ARGV.empty? end arel-4.0.0/lib/0000755000004100000410000000000012161114331013225 5ustar www-datawww-dataarel-4.0.0/lib/arel/0000755000004100000410000000000012161114331014150 5ustar www-datawww-dataarel-4.0.0/lib/arel/math.rb0000644000004100000410000000057612161114331015436 0ustar www-datawww-datamodule Arel module Math def *(other) Arel::Nodes::Multiplication.new(self, other) end def +(other) Arel::Nodes::Grouping.new(Arel::Nodes::Addition.new(self, other)) end def -(other) Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, other)) end def /(other) Arel::Nodes::Division.new(self, other) end end end arel-4.0.0/lib/arel/nodes/0000755000004100000410000000000012161114331015260 5ustar www-datawww-dataarel-4.0.0/lib/arel/nodes/in.rb0000644000004100000410000000010512161114331016207 0ustar www-datawww-datamodule Arel module Nodes class In < Equality end end end arel-4.0.0/lib/arel/nodes/unqualified_column.rb0000644000004100000410000000045512161114331021474 0ustar www-datawww-datamodule Arel module Nodes class UnqualifiedColumn < Arel::Nodes::Unary alias :attribute :expr alias :attribute= :expr= def relation @expr.relation end def column @expr.column end def name @expr.name end end end end arel-4.0.0/lib/arel/nodes/terminal.rb0000644000004100000410000000030712161114331017420 0ustar www-datawww-datamodule Arel module Nodes class Distinct < Arel::Nodes::Node def hash self.class.hash end def eql? other self.class == other.class end end end end arel-4.0.0/lib/arel/nodes/over.rb0000644000004100000410000000033112161114331016555 0ustar www-datawww-datamodule Arel module Nodes class Over < Binary include Arel::AliasPredication def initialize(left, right = nil) super(left, right) end def operator; 'OVER' end end end endarel-4.0.0/lib/arel/nodes/outer_join.rb0000644000004100000410000000012512161114331017760 0ustar www-datawww-datamodule Arel module Nodes class OuterJoin < Arel::Nodes::Join end end end arel-4.0.0/lib/arel/nodes/grouping.rb0000644000004100000410000000015112161114331017434 0ustar www-datawww-datamodule Arel module Nodes class Grouping < Unary include Arel::Predications end end end arel-4.0.0/lib/arel/nodes/binary.rb0000644000004100000410000000157512161114331017101 0ustar www-datawww-datamodule Arel module Nodes class Binary < Arel::Nodes::Node attr_accessor :left, :right def initialize left, right @left = left @right = right end def initialize_copy other super @left = @left.clone if @left @right = @right.clone if @right end def hash [@left, @right].hash end def eql? other self.class == other.class && self.left == other.left && self.right == other.right end alias :== :eql? end %w{ As Assignment Between DoesNotMatch GreaterThan GreaterThanOrEqual Join LessThan LessThanOrEqual Matches NotEqual NotIn Or Union UnionAll Intersect Except }.each do |name| const_set name, Class.new(Binary) end end end arel-4.0.0/lib/arel/nodes/infix_operation.rb0000644000004100000410000000154512161114331021007 0ustar www-datawww-datamodule Arel module Nodes class InfixOperation < Binary include Arel::Expressions include Arel::Predications include Arel::OrderPredications include Arel::AliasPredication include Arel::Math attr_reader :operator def initialize operator, left, right super(left, right) @operator = operator end end class Multiplication < InfixOperation def initialize left, right super(:*, left, right) end end class Division < InfixOperation def initialize left, right super(:/, left, right) end end class Addition < InfixOperation def initialize left, right super(:+, left, right) end end class Subtraction < InfixOperation def initialize left, right super(:-, left, right) end end end endarel-4.0.0/lib/arel/nodes/values.rb0000644000004100000410000000042012161114331017100 0ustar www-datawww-datamodule Arel module Nodes class Values < Arel::Nodes::Binary alias :expressions :left alias :expressions= :left= alias :columns :right alias :columns= :right= def initialize exprs, columns = [] super end end end end arel-4.0.0/lib/arel/nodes/join_source.rb0000644000004100000410000000052112161114331020122 0ustar www-datawww-datamodule Arel module Nodes ### # Class that represents a join source # # http://www.sqlite.org/syntaxdiagrams.html#join-source class JoinSource < Arel::Nodes::Binary def initialize single_source, joinop = [] super end def empty? !left && right.empty? end end end end arel-4.0.0/lib/arel/nodes/function.rb0000644000004100000410000000157612161114331017443 0ustar www-datawww-datamodule Arel module Nodes class Function < Arel::Nodes::Node include Arel::Expression include Arel::Predications include Arel::WindowPredications attr_accessor :expressions, :alias, :distinct def initialize expr, aliaz = nil @expressions = expr @alias = aliaz && SqlLiteral.new(aliaz) @distinct = false end def as aliaz self.alias = SqlLiteral.new(aliaz) self end def hash [@expressions, @alias, @distinct].hash end def eql? other self.class == other.class && self.expressions == other.expressions && self.alias == other.alias && self.distinct == other.distinct end end %w{ Sum Exists Max Min Avg }.each do |name| const_set(name, Class.new(Function)) end end end arel-4.0.0/lib/arel/nodes/count.rb0000644000004100000410000000032012161114331016730 0ustar www-datawww-datamodule Arel module Nodes class Count < Arel::Nodes::Function def initialize expr, distinct = false, aliaz = nil super(expr, aliaz) @distinct = distinct end end end end arel-4.0.0/lib/arel/nodes/descending.rb0000644000004100000410000000042012161114331017704 0ustar www-datawww-datamodule Arel module Nodes class Descending < Ordering def reverse Ascending.new(expr) end def direction :desc end def ascending? false end def descending? true end end end end arel-4.0.0/lib/arel/nodes/select_statement.rb0000644000004100000410000000171312161114331021152 0ustar www-datawww-datamodule Arel module Nodes class SelectStatement < Arel::Nodes::Node attr_reader :cores attr_accessor :limit, :orders, :lock, :offset, :with def initialize cores = [SelectCore.new] @cores = cores @orders = [] @limit = nil @lock = nil @offset = nil @with = nil end def initialize_copy other super @cores = @cores.map { |x| x.clone } @orders = @orders.map { |x| x.clone } end def hash [@cores, @orders, @limit, @lock, @offset, @with].hash end def eql? other self.class == other.class && self.cores == other.cores && self.orders == other.orders && self.limit == other.limit && self.lock == other.lock && self.offset == other.offset && self.with == other.with end alias :== :eql? end end end arel-4.0.0/lib/arel/nodes/inner_join.rb0000644000004100000410000000012512161114331017735 0ustar www-datawww-datamodule Arel module Nodes class InnerJoin < Arel::Nodes::Join end end end arel-4.0.0/lib/arel/nodes/named_function.rb0000644000004100000410000000056312161114331020602 0ustar www-datawww-datamodule Arel module Nodes class NamedFunction < Arel::Nodes::Function attr_accessor :name def initialize name, expr, aliaz = nil super(expr, aliaz) @name = name end def hash super ^ @name.hash end def eql? other super && self.name == other.name end alias :== :eql? end end end arel-4.0.0/lib/arel/nodes/equality.rb0000644000004100000410000000025312161114331017442 0ustar www-datawww-datamodule Arel module Nodes class Equality < Arel::Nodes::Binary def operator; :== end alias :operand1 :left alias :operand2 :right end end end arel-4.0.0/lib/arel/nodes/unary.rb0000644000004100000410000000107212161114331016743 0ustar www-datawww-datamodule Arel module Nodes class Unary < Arel::Nodes::Node attr_accessor :expr alias :value :expr def initialize expr @expr = expr end def hash @expr.hash end def eql? other self.class == other.class && self.expr == other.expr end alias :== :eql? end %w{ Bin Group Having Limit Not Offset On Ordering Top Lock DistinctOn }.each do |name| const_set(name, Class.new(Unary)) end end end arel-4.0.0/lib/arel/nodes/delete_statement.rb0000644000004100000410000000056012161114331021134 0ustar www-datawww-datamodule Arel module Nodes class DeleteStatement < Arel::Nodes::Binary alias :relation :left alias :relation= :left= alias :wheres :right alias :wheres= :right= def initialize relation = nil, wheres = [] super end def initialize_copy other super @right = @right.clone end end end end arel-4.0.0/lib/arel/nodes/false.rb0000644000004100000410000000030412161114331016674 0ustar www-datawww-datamodule Arel module Nodes class False < Arel::Nodes::Node def hash self.class.hash end def eql? other self.class == other.class end end end end arel-4.0.0/lib/arel/nodes/string_join.rb0000644000004100000410000000022512161114331020131 0ustar www-datawww-datamodule Arel module Nodes class StringJoin < Arel::Nodes::Join def initialize left, right = nil super end end end end arel-4.0.0/lib/arel/nodes/and.rb0000644000004100000410000000116312161114331016350 0ustar www-datawww-datamodule Arel module Nodes class And < Arel::Nodes::Node attr_reader :children def initialize children, right = nil unless Array === children warn "(#{caller.first}) AND nodes should be created with a list" children = [children, right] end @children = children end def left children.first end def right children[1] end def hash children.hash end def eql? other self.class == other.class && self.children == other.children end alias :== :eql? end end end arel-4.0.0/lib/arel/nodes/table_alias.rb0000644000004100000410000000057212161114331020051 0ustar www-datawww-datamodule Arel module Nodes class TableAlias < Arel::Nodes::Binary alias :name :right alias :relation :left alias :table_alias :name def [] name Attribute.new(self, name) end def table_name relation.respond_to?(:name) ? relation.name : name end def engine relation.engine end end end end arel-4.0.0/lib/arel/nodes/update_statement.rb0000644000004100000410000000160112161114331021151 0ustar www-datawww-datamodule Arel module Nodes class UpdateStatement < Arel::Nodes::Node attr_accessor :relation, :wheres, :values, :orders, :limit attr_accessor :key def initialize @relation = nil @wheres = [] @values = [] @orders = [] @limit = nil @key = nil end def initialize_copy other super @wheres = @wheres.clone @values = @values.clone end def hash [@relation, @wheres, @values, @orders, @limit, @key].hash end def eql? other self.class == other.class && self.relation == other.relation && self.wheres == other.wheres && self.values == other.values && self.orders == other.orders && self.limit == other.limit && self.key == other.key end alias :== :eql? end end end arel-4.0.0/lib/arel/nodes/with.rb0000644000004100000410000000022112161114331016553 0ustar www-datawww-datamodule Arel module Nodes class With < Arel::Nodes::Unary alias children expr end class WithRecursive < With; end end end arel-4.0.0/lib/arel/nodes/window.rb0000644000004100000410000000355612161114331017125 0ustar www-datawww-datamodule Arel module Nodes class Window < Arel::Nodes::Node include Arel::Expression attr_accessor :orders, :framing def initialize @orders = [] end def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @orders.concat expr.map { |x| String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x } self end def frame(expr) @framing = expr end def rows(expr = nil) frame(Rows.new(expr)) end def range(expr = nil) frame(Range.new(expr)) end def initialize_copy other super @orders = @orders.map { |x| x.clone } end def hash [@orders, @framing].hash end def eql? other self.class == other.class && self.orders == other.orders && self.framing == other.framing end alias :== :eql? end class NamedWindow < Window attr_accessor :name def initialize name super() @name = name end def initialize_copy other super @name = other.name.clone end def hash super ^ @name.hash end def eql? other super && self.name == other.name end alias :== :eql? end class Rows < Unary def initialize(expr = nil) super(expr) end end class Range < Unary def initialize(expr = nil) super(expr) end end class CurrentRow < Node def hash self.class.hash end def eql? other self.class == other.class end end class Preceding < Unary def initialize(expr = nil) super(expr) end end class Following < Unary def initialize(expr = nil) super(expr) end end end end arel-4.0.0/lib/arel/nodes/true.rb0000644000004100000410000000030312161114331016560 0ustar www-datawww-datamodule Arel module Nodes class True < Arel::Nodes::Node def hash self.class.hash end def eql? other self.class == other.class end end end end arel-4.0.0/lib/arel/nodes/insert_statement.rb0000644000004100000410000000123112161114331021172 0ustar www-datawww-datamodule Arel module Nodes class InsertStatement < Arel::Nodes::Node attr_accessor :relation, :columns, :values def initialize @relation = nil @columns = [] @values = nil end def initialize_copy other super @columns = @columns.clone @values = @values.clone if @values end def hash [@relation, @columns, @values].hash end def eql? other self.class == other.class && self.relation == other.relation && self.columns == other.columns && self.values == other.values end alias :== :eql? end end end arel-4.0.0/lib/arel/nodes/select_core.rb0000644000004100000410000000312312161114331020073 0ustar www-datawww-datamodule Arel module Nodes class SelectCore < Arel::Nodes::Node attr_accessor :top, :projections, :wheres, :groups, :windows attr_accessor :having, :source, :set_quantifier def initialize @source = JoinSource.new nil @top = nil # http://savage.net.au/SQL/sql-92.bnf.html#set%20quantifier @set_quantifier = nil @projections = [] @wheres = [] @groups = [] @having = nil @windows = [] end def from @source.left end def from= value @source.left = value end alias :froms= :from= alias :froms :from def initialize_copy other super @source = @source.clone if @source @projections = @projections.clone @wheres = @wheres.clone @groups = @groups.clone @having = @having.clone if @having @windows = @windows.clone end def hash [ @source, @top, @set_quantifier, @projections, @wheres, @groups, @having, @windows ].hash end def eql? other self.class == other.class && self.source == other.source && self.top == other.top && self.set_quantifier == other.set_quantifier && self.projections == other.projections && self.wheres == other.wheres && self.groups == other.groups && self.having == other.having && self.windows == other.windows end alias :== :eql? end end end arel-4.0.0/lib/arel/nodes/node.rb0000644000004100000410000000232712161114331016536 0ustar www-datawww-datamodule Arel module Nodes ### # Abstract base class for all AST nodes class Node include Arel::FactoryMethods include Enumerable ### # Factory method to create a Nodes::Not node that has the recipient of # the caller as a child. def not Nodes::Not.new self end ### # Factory method to create a Nodes::Grouping node that has an Nodes::Or # node as a child. def or right Nodes::Grouping.new Nodes::Or.new(self, right) end ### # Factory method to create an Nodes::And node. def and right Nodes::And.new [self, right] end # FIXME: this method should go away. I don't like people calling # to_sql on non-head nodes. This forces us to walk the AST until we # can find a node that has a "relation" member. # # Maybe we should just use `Table.engine`? :'( def to_sql engine = Table.engine engine.connection.visitor.accept self end # Iterate through AST, nodes will be yielded depth-first def each &block return enum_for(:each) unless block_given? ::Arel::Visitors::DepthFirst.new(block).accept self end end end end arel-4.0.0/lib/arel/nodes/ascending.rb0000644000004100000410000000041712161114331017542 0ustar www-datawww-datamodule Arel module Nodes class Ascending < Ordering def reverse Descending.new(expr) end def direction :asc end def ascending? true end def descending? false end end end end arel-4.0.0/lib/arel/nodes/sql_literal.rb0000644000004100000410000000040112161114331020113 0ustar www-datawww-datamodule Arel module Nodes class SqlLiteral < String include Arel::Expressions include Arel::Predications include Arel::AliasPredication include Arel::OrderPredications end class BindParam < SqlLiteral end end end arel-4.0.0/lib/arel/nodes/extract.rb0000644000004100000410000000121012161114331017251 0ustar www-datawww-datamodule Arel module Nodes class Extract < Arel::Nodes::Unary include Arel::Expression include Arel::Predications attr_accessor :field attr_accessor :alias def initialize expr, field, aliaz = nil super(expr) @field = field @alias = aliaz && SqlLiteral.new(aliaz) end def as aliaz self.alias = SqlLiteral.new(aliaz) self end def hash super ^ [@field, @alias].hash end def eql? other super && self.field == other.field && self.alias == other.alias end alias :== :eql? end end end arel-4.0.0/lib/arel/factory_methods.rb0000644000004100000410000000143412161114331017671 0ustar www-datawww-datamodule Arel ### # Methods for creating various nodes module FactoryMethods def create_true Arel::Nodes::True.new end def create_false Arel::Nodes::False.new end def create_table_alias relation, name Nodes::TableAlias.new(relation, name) end def create_join to, constraint = nil, klass = Nodes::InnerJoin klass.new(to, constraint) end def create_string_join to create_join to, nil, Nodes::StringJoin end def create_and clauses Nodes::And.new clauses end def create_on expr Nodes::On.new expr end def grouping expr Nodes::Grouping.new expr end ### # Create a LOWER() function def lower column Nodes::NamedFunction.new 'LOWER', [column] end end end arel-4.0.0/lib/arel/insert_manager.rb0000644000004100000410000000141512161114331017474 0ustar www-datawww-datamodule Arel class InsertManager < Arel::TreeManager def initialize engine super @ast = Nodes::InsertStatement.new end def into table @ast.relation = table self end def columns; @ast.columns end def values= val; @ast.values = val; end def insert fields return if fields.empty? if String === fields @ast.values = SqlLiteral.new(fields) else @ast.relation ||= fields.first.first.relation values = [] fields.each do |column, value| @ast.columns << column values << value end @ast.values = create_values values, @ast.columns end end def create_values values, columns Nodes::Values.new values, columns end end end arel-4.0.0/lib/arel/nodes.rb0000644000004100000410000000241112161114331015603 0ustar www-datawww-data# node require 'arel/nodes/node' require 'arel/nodes/select_statement' require 'arel/nodes/select_core' require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' # terminal require 'arel/nodes/terminal' require 'arel/nodes/true' require 'arel/nodes/false' # unary require 'arel/nodes/unary' require 'arel/nodes/grouping' require 'arel/nodes/ascending' require 'arel/nodes/descending' require 'arel/nodes/unqualified_column' require 'arel/nodes/with' # binary require 'arel/nodes/binary' require 'arel/nodes/equality' require 'arel/nodes/in' # Why is this subclassed from equality? require 'arel/nodes/join_source' require 'arel/nodes/delete_statement' require 'arel/nodes/table_alias' require 'arel/nodes/infix_operation' require 'arel/nodes/over' # nary require 'arel/nodes/and' # function # FIXME: Function + Alias can be rewritten as a Function and Alias node. # We should make Function a Unary node and deprecate the use of "aliaz" require 'arel/nodes/function' require 'arel/nodes/count' require 'arel/nodes/extract' require 'arel/nodes/values' require 'arel/nodes/named_function' # windows require 'arel/nodes/window' # joins require 'arel/nodes/inner_join' require 'arel/nodes/outer_join' require 'arel/nodes/string_join' require 'arel/nodes/sql_literal' arel-4.0.0/lib/arel/expressions.rb0000644000004100000410000000102412161114331017054 0ustar www-datawww-datamodule Arel module Expressions def count distinct = false Nodes::Count.new [self], distinct end def sum Nodes::Sum.new [self], Nodes::SqlLiteral.new('sum_id') end def maximum Nodes::Max.new [self], Nodes::SqlLiteral.new('max_id') end def minimum Nodes::Min.new [self], Nodes::SqlLiteral.new('min_id') end def average Nodes::Avg.new [self], Nodes::SqlLiteral.new('avg_id') end def extract field Nodes::Extract.new [self], field end end end arel-4.0.0/lib/arel/table.rb0000644000004100000410000000717412161114331015575 0ustar www-datawww-datamodule Arel class Table include Arel::Crud include Arel::FactoryMethods @engine = nil class << self; attr_accessor :engine; end attr_accessor :name, :engine, :aliases, :table_alias # TableAlias and Table both have a #table_name which is the name of the underlying table alias :table_name :name def initialize name, engine = Table.engine @name = name.to_s @engine = engine @columns = nil @aliases = [] @table_alias = nil @primary_key = nil if Hash === engine @engine = engine[:engine] || Table.engine # Sometime AR sends an :as parameter to table, to let the table know # that it is an Alias. We may want to override new, and return a # TableAlias node? @table_alias = engine[:as] unless engine[:as].to_s == @name end end def primary_key if $VERBOSE warn <<-eowarn primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0 eowarn end @primary_key ||= begin primary_key_name = @engine.connection.primary_key(name) # some tables might be without primary key primary_key_name && self[primary_key_name] end end def alias name = "#{self.name}_2" Nodes::TableAlias.new(self, name).tap do |node| @aliases << node end end def from table SelectManager.new(@engine, table) end def joins manager if $VERBOSE warn "joins is deprecated and will be removed in 4.0.0" warn "please remove your call to joins from #{caller.first}" end nil end def join relation, klass = Nodes::InnerJoin return from(self) unless relation case relation when String, Nodes::SqlLiteral raise if relation.blank? klass = Nodes::StringJoin end from(self).join(relation, klass) end def group *columns from(self).group(*columns) end def order *expr from(self).order(*expr) end def where condition from(self).where condition end def project *things from(self).project(*things) end def take amount from(self).take amount end def skip amount from(self).skip amount end def having expr from(self).having expr end def columns if $VERBOSE warn <<-eowarn (#{caller.first}) Arel::Table#columns is deprecated and will be removed in Arel 4.0.0 with no replacement. PEW PEW PEW!!! eowarn end @columns ||= attributes_for @engine.connection.columns(@name, "#{@name} Columns") end def [] name ::Arel::Attribute.new self, name end def select_manager SelectManager.new(@engine) end def insert_manager InsertManager.new(@engine) end def hash [@name, @engine, @aliases, @table_alias].hash end def eql? other self.class == other.class && self.name == other.name && self.engine == other.engine && self.aliases == other.aliases && self.table_alias == other.table_alias end alias :== :eql? private def attributes_for columns return nil unless columns columns.map do |column| Attributes.for(column).new self, column.name.to_sym end end @@table_cache = nil def self.table_cache engine # :nodoc: if $VERBOSE warn <<-eowarn (#{caller.first}) Arel::Table.table_cache is deprecated and will be removed in Arel 4.0.0 with no replacement. PEW PEW PEW!!! eowarn end @@table_cache ||= Hash[engine.connection.tables.map { |x| [x,true] }] end end end arel-4.0.0/lib/arel/compatibility/0000755000004100000410000000000012161114331017021 5ustar www-datawww-dataarel-4.0.0/lib/arel/compatibility/wheres.rb0000644000004100000410000000112612161114331020643 0ustar www-datawww-datamodule Arel module Compatibility # :nodoc: class Wheres # :nodoc: include Enumerable module Value # :nodoc: attr_accessor :visitor def value visitor.accept self end def name super.to_sym end end def initialize engine, collection @engine = engine @collection = collection end def each to_sql = Visitors::ToSql.new @engine @collection.each { |c| c.extend(Value) c.visitor = to_sql yield c } end end end end arel-4.0.0/lib/arel/delete_manager.rb0000644000004100000410000000045012161114331017430 0ustar www-datawww-datamodule Arel class DeleteManager < Arel::TreeManager def initialize engine super @ast = Nodes::DeleteStatement.new @ctx = @ast end def from relation @ast.relation = relation self end def wheres= list @ast.wheres = list end end end arel-4.0.0/lib/arel/crud.rb0000644000004100000410000000314412161114331015434 0ustar www-datawww-datamodule Arel ### # FIXME hopefully we can remove this module Crud def compile_update values um = UpdateManager.new @engine if Nodes::SqlLiteral === values relation = @ctx.from else relation = values.first.first.relation end um.table relation um.set values um.take @ast.limit.expr if @ast.limit um.order(*@ast.orders) um.wheres = @ctx.wheres um end # FIXME: this method should go away def update values if $VERBOSE warn <<-eowarn update (#{caller.first}) is deprecated and will be removed in Arel 4.0.0. Please switch to `compile_update` eowarn end um = compile_update values @engine.connection.update um.to_sql, 'AREL' end def compile_insert values im = create_insert im.insert values im end def create_insert InsertManager.new @engine end # FIXME: this method should go away def insert values if $VERBOSE warn <<-eowarn insert (#{caller.first}) is deprecated and will be removed in Arel 4.0.0. Please switch to `compile_insert` eowarn end @engine.connection.insert compile_insert(values).to_sql end def compile_delete dm = DeleteManager.new @engine dm.wheres = @ctx.wheres dm.from @ctx.froms dm end def delete if $VERBOSE warn <<-eowarn delete (#{caller.first}) is deprecated and will be removed in Arel 4.0.0. Please switch to `compile_delete` eowarn end @engine.connection.delete compile_delete.to_sql, 'AREL' end end end arel-4.0.0/lib/arel/visitors/0000755000004100000410000000000012161114331016032 5ustar www-datawww-dataarel-4.0.0/lib/arel/visitors/ibm_db.rb0000644000004100000410000000030612161114331017572 0ustar www-datawww-datamodule Arel module Visitors class IBM_DB < Arel::Visitors::ToSql private def visit_Arel_Nodes_Limit o "FETCH FIRST #{visit o.expr} ROWS ONLY" end end end end arel-4.0.0/lib/arel/visitors/where_sql.rb0000644000004100000410000000031312161114331020345 0ustar www-datawww-datamodule Arel module Visitors class WhereSql < Arel::Visitors::ToSql def visit_Arel_Nodes_SelectCore o "WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" end end end end arel-4.0.0/lib/arel/visitors/mysql.rb0000644000004100000410000000320412161114331017523 0ustar www-datawww-datamodule Arel module Visitors class MySQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Union o, suppress_parens = false left_result = case o.left when Arel::Nodes::Union visit_Arel_Nodes_Union o.left, true else visit o.left end right_result = case o.right when Arel::Nodes::Union visit_Arel_Nodes_Union o.right, true else visit o.right end if suppress_parens "#{left_result} UNION #{right_result}" else "( #{left_result} UNION #{right_result} )" end end def visit_Arel_Nodes_Bin o "BINARY #{visit o.expr}" end ### # :'( # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 def visit_Arel_Nodes_SelectStatement o o.limit = Arel::Nodes::Limit.new(18446744073709551615) if o.offset && !o.limit super end def visit_Arel_Nodes_SelectCore o o.froms ||= Arel.sql('DUAL') super end def visit_Arel_Nodes_UpdateStatement o [ "UPDATE #{visit o.relation}", ("SET #{o.values.map { |value| visit value }.join ', '}" unless o.values.empty?), ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?), ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), (visit(o.limit) if o.limit), ].compact.join ' ' end end end end arel-4.0.0/lib/arel/visitors/to_sql.rb0000644000004100000410000004133712161114331017670 0ustar www-datawww-datarequire 'bigdecimal' require 'date' module Arel module Visitors class ToSql < Arel::Visitors::Visitor ## # This is some roflscale crazy stuff. I'm roflscaling this because # building SQL queries is a hotspot. I will explain the roflscale so that # others will not rm this code. # # In YARV, string literals in a method body will get duped when the byte # code is executed. Let's take a look: # # > puts RubyVM::InstructionSequence.new('def foo; "bar"; end').disasm # # == disasm: >===== # 0000 trace 8 # 0002 trace 1 # 0004 putstring "bar" # 0006 trace 16 # 0008 leave # # The `putstring` bytecode will dup the string and push it on the stack. # In many cases in our SQL visitor, that string is never mutated, so there # is no need to dup the literal. # # If we change to a constant lookup, the string will not be duped, and we # can reduce the objects in our system: # # > puts RubyVM::InstructionSequence.new('BAR = "bar"; def foo; BAR; end').disasm # # == disasm: >======== # 0000 trace 8 # 0002 trace 1 # 0004 getinlinecache 11, # 0007 getconstant :BAR # 0009 setinlinecache # 0011 trace 16 # 0013 leave # # `getconstant` should be a hash lookup, and no object is duped when the # value of the constant is pushed on the stack. Hence the crazy # constants below. WHERE = ' WHERE ' # :nodoc: SPACE = ' ' # :nodoc: COMMA = ', ' # :nodoc: GROUP_BY = ' GROUP BY ' # :nodoc: ORDER_BY = ' ORDER BY ' # :nodoc: WINDOW = ' WINDOW ' # :nodoc: AND = ' AND ' # :nodoc: DISTINCT = 'DISTINCT' # :nodoc: attr_accessor :last_column def initialize connection @connection = connection @schema_cache = connection.schema_cache @quoted_tables = {} @quoted_columns = {} @last_column = nil end def accept object self.last_column = nil super end private def visit_Arel_Nodes_DeleteStatement o [ "DELETE FROM #{visit o.relation}", ("WHERE #{o.wheres.map { |x| visit x }.join AND}" unless o.wheres.empty?) ].compact.join ' ' end # FIXME: we should probably have a 2-pass visitor for this def build_subselect key, o stmt = Nodes::SelectStatement.new core = stmt.cores.first core.froms = o.relation core.wheres = o.wheres core.projections = [key] stmt.limit = o.limit stmt.orders = o.orders stmt end def visit_Arel_Nodes_UpdateStatement o if o.orders.empty? && o.limit.nil? wheres = o.wheres else key = o.key unless key warn(<<-eowarn) if $VERBOSE (#{caller.first}) Using UpdateManager without setting UpdateManager#key is deprecated and support will be removed in Arel 4.0.0. Please set the primary key on UpdateManager using UpdateManager#key= eowarn key = o.relation.primary_key end wheres = [Nodes::In.new(key, [build_subselect(key, o)])] end [ "UPDATE #{visit o.relation}", ("SET #{o.values.map { |value| visit value }.join ', '}" unless o.values.empty?), ("WHERE #{wheres.map { |x| visit x }.join ' AND '}" unless wheres.empty?), ].compact.join ' ' end def visit_Arel_Nodes_InsertStatement o [ "INSERT INTO #{visit o.relation}", ("(#{o.columns.map { |x| quote_column_name x.name }.join ', '})" unless o.columns.empty?), (visit o.values if o.values), ].compact.join ' ' end def visit_Arel_Nodes_Exists o "EXISTS (#{visit o.expressions})#{ o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_True o "TRUE" end def visit_Arel_Nodes_False o "FALSE" end def table_exists? name @schema_cache.table_exists? name end def column_for attr name = attr.name.to_s table = attr.relation.table_name return nil unless table_exists? table column_cache(table)[name] end def column_cache(table) @schema_cache.columns_hash(table) end def visit_Arel_Nodes_Values o "VALUES (#{o.expressions.zip(o.columns).map { |value, attr| if Nodes::SqlLiteral === value visit value else quote(value, attr && column_for(attr)) end }.join ', '})" end def visit_Arel_Nodes_SelectStatement o str = '' if o.with str << visit(o.with) str << SPACE end o.cores.each { |x| str << visit_Arel_Nodes_SelectCore(x) } unless o.orders.empty? str << SPACE str << ORDER_BY len = o.orders.length - 1 o.orders.each_with_index { |x, i| str << visit(x) str << COMMA unless len == i } end str << " #{visit(o.limit)}" if o.limit str << " #{visit(o.offset)}" if o.offset str << " #{visit(o.lock)}" if o.lock str.strip! str end def visit_Arel_Nodes_SelectCore o str = "SELECT" str << " #{visit(o.top)}" if o.top str << " #{visit(o.set_quantifier)}" if o.set_quantifier unless o.projections.empty? str << SPACE len = o.projections.length - 1 o.projections.each_with_index do |x, i| str << visit(x) str << COMMA unless len == i end end str << " FROM #{visit(o.source)}" if o.source && !o.source.empty? unless o.wheres.empty? str << WHERE len = o.wheres.length - 1 o.wheres.each_with_index do |x, i| str << visit(x) str << AND unless len == i end end unless o.groups.empty? str << GROUP_BY len = o.groups.length - 1 o.groups.each_with_index do |x, i| str << visit(x) str << COMMA unless len == i end end str << " #{visit(o.having)}" if o.having unless o.windows.empty? str << WINDOW len = o.windows.length - 1 o.windows.each_with_index do |x, i| str << visit(x) str << COMMA unless len == i end end str end def visit_Arel_Nodes_Bin o visit o.expr end def visit_Arel_Nodes_Distinct o DISTINCT end def visit_Arel_Nodes_DistinctOn o raise NotImplementedError, 'DISTINCT ON not implemented for this db' end def visit_Arel_Nodes_With o "WITH #{o.children.map { |x| visit x }.join(', ')}" end def visit_Arel_Nodes_WithRecursive o "WITH RECURSIVE #{o.children.map { |x| visit x }.join(', ')}" end def visit_Arel_Nodes_Union o "( #{visit o.left} UNION #{visit o.right} )" end def visit_Arel_Nodes_UnionAll o "( #{visit o.left} UNION ALL #{visit o.right} )" end def visit_Arel_Nodes_Intersect o "( #{visit o.left} INTERSECT #{visit o.right} )" end def visit_Arel_Nodes_Except o "( #{visit o.left} EXCEPT #{visit o.right} )" end def visit_Arel_Nodes_NamedWindow o "#{quote_column_name o.name} AS #{visit_Arel_Nodes_Window o}" end def visit_Arel_Nodes_Window o s = [ ("ORDER BY #{o.orders.map { |x| visit(x) }.join(', ')}" unless o.orders.empty?), (visit o.framing if o.framing) ].compact.join ' ' "(#{s})" end def visit_Arel_Nodes_Rows o if o.expr "ROWS #{visit o.expr}" else "ROWS" end end def visit_Arel_Nodes_Range o if o.expr "RANGE #{visit o.expr}" else "RANGE" end end def visit_Arel_Nodes_Preceding o "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} PRECEDING" end def visit_Arel_Nodes_Following o "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} FOLLOWING" end def visit_Arel_Nodes_CurrentRow o "CURRENT ROW" end def visit_Arel_Nodes_Over o case o.right when nil "#{visit o.left} OVER ()" when Arel::Nodes::SqlLiteral "#{visit o.left} OVER #{visit o.right}" when String, Symbol "#{visit o.left} OVER #{quote_column_name o.right.to_s}" else "#{visit o.left} OVER #{visit o.right}" end end def visit_Arel_Nodes_Having o "HAVING #{visit o.expr}" end def visit_Arel_Nodes_Offset o "OFFSET #{visit o.expr}" end def visit_Arel_Nodes_Limit o "LIMIT #{visit o.expr}" end # FIXME: this does nothing on most databases, but does on MSSQL def visit_Arel_Nodes_Top o "" end def visit_Arel_Nodes_Lock o visit o.expr end def visit_Arel_Nodes_Grouping o "(#{visit o.expr})" end def visit_Arel_SelectManager o "(#{o.to_sql.rstrip})" end def visit_Arel_Nodes_Ascending o "#{visit o.expr} ASC" end def visit_Arel_Nodes_Descending o "#{visit o.expr} DESC" end def visit_Arel_Nodes_Group o visit o.expr end def visit_Arel_Nodes_NamedFunction o "#{o.name}(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_Extract o "EXTRACT(#{o.field.to_s.upcase} FROM #{visit o.expr})#{o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_Count o "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_Sum o "SUM(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_Max o "MAX(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_Min o "MIN(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_Avg o "AVG(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_TableAlias o "#{visit o.relation} #{quote_table_name o.name}" end def visit_Arel_Nodes_Between o "#{visit o.left} BETWEEN #{visit o.right}" end def visit_Arel_Nodes_GreaterThanOrEqual o "#{visit o.left} >= #{visit o.right}" end def visit_Arel_Nodes_GreaterThan o "#{visit o.left} > #{visit o.right}" end def visit_Arel_Nodes_LessThanOrEqual o "#{visit o.left} <= #{visit o.right}" end def visit_Arel_Nodes_LessThan o "#{visit o.left} < #{visit o.right}" end def visit_Arel_Nodes_Matches o "#{visit o.left} LIKE #{visit o.right}" end def visit_Arel_Nodes_DoesNotMatch o "#{visit o.left} NOT LIKE #{visit o.right}" end def visit_Arel_Nodes_JoinSource o [ (visit(o.left) if o.left), o.right.map { |j| visit j }.join(' ') ].compact.join ' ' end def visit_Arel_Nodes_StringJoin o visit o.left end def visit_Arel_Nodes_OuterJoin o "LEFT OUTER JOIN #{visit o.left} #{visit o.right}" end def visit_Arel_Nodes_InnerJoin o s = "INNER JOIN #{visit o.left}" if o.right s << SPACE s << visit(o.right) end s end def visit_Arel_Nodes_On o "ON #{visit o.expr}" end def visit_Arel_Nodes_Not o "NOT (#{visit o.expr})" end def visit_Arel_Table o if o.table_alias "#{quote_table_name o.name} #{quote_table_name o.table_alias}" else quote_table_name o.name end end def visit_Arel_Nodes_In o if Array === o.right && o.right.empty? '1=0' else "#{visit o.left} IN (#{visit o.right})" end end def visit_Arel_Nodes_NotIn o if Array === o.right && o.right.empty? '1=1' else "#{visit o.left} NOT IN (#{visit o.right})" end end def visit_Arel_Nodes_And o o.children.map { |x| visit x }.join ' AND ' end def visit_Arel_Nodes_Or o "#{visit o.left} OR #{visit o.right}" end def visit_Arel_Nodes_Assignment o right = quote(o.right, column_for(o.left)) "#{visit o.left} = #{right}" end def visit_Arel_Nodes_Equality o right = o.right if right.nil? "#{visit o.left} IS NULL" else "#{visit o.left} = #{visit right}" end end def visit_Arel_Nodes_NotEqual o right = o.right if right.nil? "#{visit o.left} IS NOT NULL" else "#{visit o.left} != #{visit right}" end end def visit_Arel_Nodes_As o "#{visit o.left} AS #{visit o.right}" end def visit_Arel_Nodes_UnqualifiedColumn o "#{quote_column_name o.name}" end def visit_Arel_Attributes_Attribute o self.last_column = column_for o join_name = o.relation.table_alias || o.relation.name "#{quote_table_name join_name}.#{quote_column_name o.name}" end alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute def literal o; o end alias :visit_Arel_Nodes_BindParam :literal alias :visit_Arel_Nodes_SqlLiteral :literal alias :visit_Arel_SqlLiteral :literal # This is deprecated alias :visit_Bignum :literal alias :visit_Fixnum :literal def quoted o quote(o, last_column) end alias :visit_ActiveSupport_Multibyte_Chars :quoted alias :visit_ActiveSupport_StringInquirer :quoted alias :visit_BigDecimal :quoted alias :visit_Class :quoted alias :visit_Date :quoted alias :visit_DateTime :quoted alias :visit_FalseClass :quoted alias :visit_Float :quoted alias :visit_Hash :quoted alias :visit_NilClass :quoted alias :visit_String :quoted alias :visit_Symbol :quoted alias :visit_Time :quoted alias :visit_TrueClass :quoted def visit_Arel_Nodes_InfixOperation o "#{visit o.left} #{o.operator} #{visit o.right}" end alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation alias :visit_Arel_Nodes_Subtraction :visit_Arel_Nodes_InfixOperation alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation def visit_Array o o.map { |x| visit x }.join(', ') end def quote value, column = nil return value if Arel::Nodes::SqlLiteral === value @connection.quote value, column end def quote_table_name name return name if Arel::Nodes::SqlLiteral === name @quoted_tables[name] ||= @connection.quote_table_name(name) end def quote_column_name name @quoted_columns[name] ||= Arel::Nodes::SqlLiteral === name ? name : @connection.quote_column_name(name) end end end end arel-4.0.0/lib/arel/visitors/order_clauses.rb0000644000004100000410000000031212161114331021205 0ustar www-datawww-datamodule Arel module Visitors class OrderClauses < Arel::Visitors::ToSql private def visit_Arel_Nodes_SelectStatement o o.orders.map { |x| visit x } end end end end arel-4.0.0/lib/arel/visitors/dot.rb0000644000004100000410000001707612161114331017160 0ustar www-datawww-datamodule Arel module Visitors class Dot < Arel::Visitors::Visitor class Node # :nodoc: attr_accessor :name, :id, :fields def initialize name, id, fields = [] @name = name @id = id @fields = fields end end class Edge < Struct.new :name, :from, :to # :nodoc: end def initialize @nodes = [] @edges = [] @node_stack = [] @edge_stack = [] @seen = {} end def accept object super to_dot end private def visit_Arel_Nodes_Ordering o visit_edge o, "expr" end def visit_Arel_Nodes_TableAlias o visit_edge o, "name" visit_edge o, "relation" end def visit_Arel_Nodes_Count o visit_edge o, "expressions" visit_edge o, "distinct" end def visit_Arel_Nodes_Values o visit_edge o, "expressions" end def visit_Arel_Nodes_StringJoin o visit_edge o, "left" end def visit_Arel_Nodes_InnerJoin o visit_edge o, "left" visit_edge o, "right" end alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin def visit_Arel_Nodes_DeleteStatement o visit_edge o, "relation" visit_edge o, "wheres" end def unary o visit_edge o, "expr" end alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary alias :visit_Arel_Nodes_Not :unary alias :visit_Arel_Nodes_Offset :unary alias :visit_Arel_Nodes_On :unary alias :visit_Arel_Nodes_Top :unary alias :visit_Arel_Nodes_UnqualifiedColumn :unary alias :visit_Arel_Nodes_Preceding :unary alias :visit_Arel_Nodes_Following :unary alias :visit_Arel_Nodes_Rows :unary alias :visit_Arel_Nodes_Range :unary def window o visit_edge o, "orders" visit_edge o, "framing" end alias :visit_Arel_Nodes_Window :window def named_window o visit_edge o, "orders" visit_edge o, "framing" visit_edge o, "name" end alias :visit_Arel_Nodes_NamedWindow :named_window def function o visit_edge o, "expressions" visit_edge o, "distinct" visit_edge o, "alias" end alias :visit_Arel_Nodes_Exists :function alias :visit_Arel_Nodes_Min :function alias :visit_Arel_Nodes_Max :function alias :visit_Arel_Nodes_Avg :function alias :visit_Arel_Nodes_Sum :function def extract o visit_edge o, "expressions" visit_edge o, "alias" end alias :visit_Arel_Nodes_Extract :extract def visit_Arel_Nodes_NamedFunction o visit_edge o, "name" visit_edge o, "expressions" visit_edge o, "distinct" visit_edge o, "alias" end def visit_Arel_Nodes_InsertStatement o visit_edge o, "relation" visit_edge o, "columns" visit_edge o, "values" end def visit_Arel_Nodes_SelectCore o visit_edge o, "source" visit_edge o, "projections" visit_edge o, "wheres" visit_edge o, "windows" end def visit_Arel_Nodes_SelectStatement o visit_edge o, "cores" visit_edge o, "limit" visit_edge o, "orders" visit_edge o, "offset" end def visit_Arel_Nodes_UpdateStatement o visit_edge o, "relation" visit_edge o, "wheres" visit_edge o, "values" end def visit_Arel_Table o visit_edge o, "name" end def visit_Arel_Attribute o visit_edge o, "relation" visit_edge o, "name" end alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute alias :visit_Arel_Attributes_Float :visit_Arel_Attribute alias :visit_Arel_Attributes_String :visit_Arel_Attribute alias :visit_Arel_Attributes_Time :visit_Arel_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute def nary o o.children.each_with_index do |x,i| edge(i) { visit x } end end alias :visit_Arel_Nodes_And :nary def binary o visit_edge o, "left" visit_edge o, "right" end alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary alias :visit_Arel_Nodes_Between :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary alias :visit_Arel_Nodes_GreaterThan :binary alias :visit_Arel_Nodes_GreaterThanOrEqual :binary alias :visit_Arel_Nodes_In :binary alias :visit_Arel_Nodes_JoinSource :binary alias :visit_Arel_Nodes_LessThan :binary alias :visit_Arel_Nodes_LessThanOrEqual :binary alias :visit_Arel_Nodes_Matches :binary alias :visit_Arel_Nodes_NotEqual :binary alias :visit_Arel_Nodes_NotIn :binary alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_Over :binary def visit_String o @node_stack.last.fields << o end alias :visit_Time :visit_String alias :visit_Date :visit_String alias :visit_DateTime :visit_String alias :visit_NilClass :visit_String alias :visit_TrueClass :visit_String alias :visit_FalseClass :visit_String alias :visit_Arel_SqlLiteral :visit_String alias :visit_Arel_Nodes_BindParam :visit_String alias :visit_Fixnum :visit_String alias :visit_BigDecimal :visit_String alias :visit_Float :visit_String alias :visit_Symbol :visit_String alias :visit_Arel_Nodes_SqlLiteral :visit_String def visit_Hash o o.each_with_index do |pair, i| edge("pair_#{i}") { visit pair } end end def visit_Array o o.each_with_index do |x,i| edge(i) { visit x } end end def visit_edge o, method edge(method) { visit o.send(method) } end def visit o if node = @seen[o.object_id] @edge_stack.last.to = node return end node = Node.new(o.class.name, o.object_id) @seen[node.id] = node @nodes << node with_node node do super end end def edge name edge = Edge.new(name, @node_stack.last) @edge_stack.push edge @edges << edge yield @edge_stack.pop end def with_node node if edge = @edge_stack.last edge.to = node end @node_stack.push node yield @node_stack.pop end def quote string string.to_s.gsub('"', '\"') end def to_dot "digraph \"Arel\" {\nnode [width=0.375,height=0.25,shape=record];\n" + @nodes.map { |node| label = "#{node.name}" node.fields.each_with_index do |field, i| label << "|#{quote field}" end "#{node.id} [label=\"#{label}\"];" }.join("\n") + "\n" + @edges.map { |edge| "#{edge.from.id} -> #{edge.to.id} [label=\"#{edge.name}\"];" }.join("\n") + "\n}" end end end end arel-4.0.0/lib/arel/visitors/oracle.rb0000644000004100000410000000716412161114331017634 0ustar www-datawww-datamodule Arel module Visitors class Oracle < Arel::Visitors::ToSql private def visit_Arel_Nodes_SelectStatement o o = order_hacks(o) # if need to select first records without ORDER BY and GROUP BY and without DISTINCT # then can use simple ROWNUM in WHERE clause if o.limit && o.orders.empty? && !o.offset && o.cores.first.projections.first !~ /^DISTINCT / o.cores.last.wheres.push Nodes::LessThanOrEqual.new( Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr ) return super end if o.limit && o.offset o = o.dup limit = o.limit.expr.to_i offset = o.offset o.offset = nil sql = super(o) return <<-eosql SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (#{sql}) raw_sql_ WHERE rownum <= #{offset.expr.to_i + limit} ) WHERE #{visit offset} eosql end if o.limit o = o.dup limit = o.limit.expr return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{visit limit}" end if o.offset o = o.dup offset = o.offset o.offset = nil sql = super(o) return <<-eosql SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (#{sql}) raw_sql_ ) WHERE #{visit offset} eosql end super end def visit_Arel_Nodes_Limit o end def visit_Arel_Nodes_Offset o "raw_rnum_ > #{visit o.expr}" end def visit_Arel_Nodes_Except o "( #{visit o.left} MINUS #{visit o.right} )" end def visit_Arel_Nodes_UpdateStatement o # Oracle does not allow ORDER BY/LIMIT in UPDATEs. if o.orders.any? && o.limit.nil? # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided, # otherwise let the user deal with the error o = o.dup o.orders = [] end super end ### # Hacks for the order clauses specific to Oracle def order_hacks o return o if o.orders.empty? return o unless o.cores.any? do |core| core.projections.any? do |projection| /DISTINCT.*FIRST_VALUE/ === projection end end # Previous version with join and split broke ORDER BY clause # if it contained functions with several arguments (separated by ','). # # orders = o.orders.map { |x| visit x }.join(', ').split(',') orders = o.orders.map do |x| string = visit x if string.include?(',') split_order_string(string) else string end end.flatten o.orders = [] orders.each_with_index do |order, i| o.orders << Nodes::SqlLiteral.new("alias_#{i}__#{' DESC' if /\bdesc$/i === order}") end o end # Split string by commas but count opening and closing brackets # and ignore commas inside brackets. def split_order_string(string) array = [] i = 0 string.split(',').each do |part| if array[i] array[i] << ',' << part else # to ensure that array[i] will be String and not Arel::Nodes::SqlLiteral array[i] = '' << part end i += 1 if array[i].count('(') == array[i].count(')') end array end end end end arel-4.0.0/lib/arel/visitors/mssql.rb0000644000004100000410000000450012161114331017515 0ustar www-datawww-datamodule Arel module Visitors class MSSQL < Arel::Visitors::ToSql private # `top` wouldn't really work here. I.e. User.select("distinct first_name").limit(10) would generate # "select top 10 distinct first_name from users", which is invalid query! it should be # "select distinct top 10 first_name from users" def visit_Arel_Nodes_Top o "" end def visit_Arel_Nodes_SelectStatement o if !o.limit && !o.offset return super o end select_order_by = "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty? is_select_count = false sql = o.cores.map { |x| core_order_by = select_order_by || determine_order_by(x) if select_count? x x.projections = [row_num_literal(core_order_by)] is_select_count = true else x.projections << row_num_literal(core_order_by) end visit_Arel_Nodes_SelectCore x }.join sql = "SELECT _t.* FROM (#{sql}) as _t WHERE #{get_offset_limit_clause(o)}" # fixme count distinct wouldn't work with limit or offset sql = "SELECT COUNT(1) as count_id FROM (#{sql}) AS subquery" if is_select_count sql end def get_offset_limit_clause o first_row = o.offset ? o.offset.expr.to_i + 1 : 1 last_row = o.limit ? o.limit.expr.to_i - 1 + first_row : nil if last_row " _row_num BETWEEN #{first_row} AND #{last_row}" else " _row_num >= #{first_row}" end end def determine_order_by x unless x.groups.empty? "ORDER BY #{x.groups.map { |g| visit g }.join ', ' }" else "ORDER BY #{find_left_table_pk(x.froms)}" end end def row_num_literal order_by Nodes::SqlLiteral.new("ROW_NUMBER() OVER (#{order_by}) as _row_num") end def select_count? x x.projections.length == 1 && Arel::Nodes::Count === x.projections.first end # fixme raise exception of there is no pk? # fixme!! Table.primary_key will be depricated. What is the replacement?? def find_left_table_pk o return visit o.primary_key if o.instance_of? Arel::Table find_left_table_pk o.left if o.kind_of? Arel::Nodes::Join end end end end arel-4.0.0/lib/arel/visitors/bind_visitor.rb0000644000004100000410000000110212161114331021044 0ustar www-datawww-datamodule Arel module Visitors module BindVisitor def initialize target @block = nil super end def accept node, &block @block = block if block_given? super end private def visit_Arel_Nodes_Assignment o if o.right.is_a? Arel::Nodes::BindParam "#{visit o.left} = #{visit o.right}" else super end end def visit_Arel_Nodes_BindParam o if @block @block.call else super end end end end end arel-4.0.0/lib/arel/visitors/informix.rb0000644000004100000410000000207612161114331020217 0ustar www-datawww-datamodule Arel module Visitors class Informix < Arel::Visitors::ToSql private def visit_Arel_Nodes_SelectStatement o [ "SELECT", (visit(o.offset) if o.offset), (visit(o.limit) if o.limit), o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), (visit(o.lock) if o.lock), ].compact.join ' ' end def visit_Arel_Nodes_SelectCore o [ "#{o.projections.map { |x| visit x }.join ', '}", ("FROM #{visit(o.source)}" if o.source && !o.source.empty?), ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.empty?), ("GROUP BY #{o.groups.map { |x| visit x }.join ', ' }" unless o.groups.empty?), (visit(o.having) if o.having), ].compact.join ' ' end def visit_Arel_Nodes_Offset o "SKIP #{visit o.expr}" end def visit_Arel_Nodes_Limit o "LIMIT #{visit o.expr}" end end end end arel-4.0.0/lib/arel/visitors/visitor.rb0000644000004100000410000000133512161114331020060 0ustar www-datawww-datamodule Arel module Visitors class Visitor def accept object visit object end private DISPATCH = Hash.new do |hash, klass| hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" end def dispatch DISPATCH end def visit object send dispatch[object.class], object rescue NoMethodError => e raise e if respond_to?(dispatch[object.class], true) superklass = object.class.ancestors.find { |klass| respond_to?(dispatch[klass], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass dispatch[object.class] = dispatch[superklass] retry end end end end arel-4.0.0/lib/arel/visitors/depth_first.rb0000644000004100000410000001312112161114331020670 0ustar www-datawww-datamodule Arel module Visitors class DepthFirst < Arel::Visitors::Visitor def initialize block = nil @block = block || Proc.new end private def visit o super @block.call o end def unary o visit o.expr end alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary alias :visit_Arel_Nodes_Not :unary alias :visit_Arel_Nodes_Offset :unary alias :visit_Arel_Nodes_On :unary alias :visit_Arel_Nodes_Ordering :unary alias :visit_Arel_Nodes_Ascending :unary alias :visit_Arel_Nodes_Descending :unary alias :visit_Arel_Nodes_Top :unary alias :visit_Arel_Nodes_UnqualifiedColumn :unary def function o visit o.expressions visit o.alias visit o.distinct end alias :visit_Arel_Nodes_Avg :function alias :visit_Arel_Nodes_Exists :function alias :visit_Arel_Nodes_Max :function alias :visit_Arel_Nodes_Min :function alias :visit_Arel_Nodes_Sum :function def visit_Arel_Nodes_NamedFunction o visit o.name visit o.expressions visit o.distinct visit o.alias end def visit_Arel_Nodes_Count o visit o.expressions visit o.alias visit o.distinct end def nary o o.children.each { |child| visit child } end alias :visit_Arel_Nodes_And :nary def binary o visit o.left visit o.right end alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary alias :visit_Arel_Nodes_Between :binary alias :visit_Arel_Nodes_DeleteStatement :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary alias :visit_Arel_Nodes_GreaterThan :binary alias :visit_Arel_Nodes_GreaterThanOrEqual :binary alias :visit_Arel_Nodes_In :binary alias :visit_Arel_Nodes_InfixOperation :binary alias :visit_Arel_Nodes_JoinSource :binary alias :visit_Arel_Nodes_InnerJoin :binary alias :visit_Arel_Nodes_LessThan :binary alias :visit_Arel_Nodes_LessThanOrEqual :binary alias :visit_Arel_Nodes_Matches :binary alias :visit_Arel_Nodes_NotEqual :binary alias :visit_Arel_Nodes_NotIn :binary alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_OuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary def visit_Arel_Nodes_StringJoin o visit o.left end def visit_Arel_Attribute o visit o.relation visit o.name end alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute alias :visit_Arel_Attributes_Float :visit_Arel_Attribute alias :visit_Arel_Attributes_String :visit_Arel_Attribute alias :visit_Arel_Attributes_Time :visit_Arel_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute alias :visit_Arel_Attributes_Decimal :visit_Arel_Attribute def visit_Arel_Table o visit o.name end def terminal o end alias :visit_ActiveSupport_Multibyte_Chars :terminal alias :visit_ActiveSupport_StringInquirer :terminal alias :visit_Arel_Nodes_Lock :terminal alias :visit_Arel_Nodes_Node :terminal alias :visit_Arel_Nodes_SqlLiteral :terminal alias :visit_Arel_Nodes_BindParam :terminal alias :visit_Arel_Nodes_Window :terminal alias :visit_Arel_SqlLiteral :terminal alias :visit_BigDecimal :terminal alias :visit_Bignum :terminal alias :visit_Class :terminal alias :visit_Date :terminal alias :visit_DateTime :terminal alias :visit_FalseClass :terminal alias :visit_Fixnum :terminal alias :visit_Float :terminal alias :visit_NilClass :terminal alias :visit_String :terminal alias :visit_Symbol :terminal alias :visit_Time :terminal alias :visit_TrueClass :terminal def visit_Arel_Nodes_InsertStatement o visit o.relation visit o.columns visit o.values end def visit_Arel_Nodes_SelectCore o visit o.projections visit o.source visit o.wheres visit o.groups visit o.windows visit o.having end def visit_Arel_Nodes_SelectStatement o visit o.cores visit o.orders visit o.limit visit o.lock visit o.offset end def visit_Arel_Nodes_UpdateStatement o visit o.relation visit o.values visit o.wheres visit o.orders visit o.limit end def visit_Array o o.each { |i| visit i } end def visit_Hash o o.each { |k,v| visit(k); visit(v) } end end end end arel-4.0.0/lib/arel/visitors/sqlite.rb0000644000004100000410000000051112161114331017655 0ustar www-datawww-datamodule Arel module Visitors class SQLite < Arel::Visitors::ToSql private # Locks are not supported in SQLite def visit_Arel_Nodes_Lock o end def visit_Arel_Nodes_SelectStatement o o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit super end end end end arel-4.0.0/lib/arel/visitors/join_sql.rb0000644000004100000410000000074412161114331020202 0ustar www-datawww-datamodule Arel module Visitors ### # This class produces SQL for JOIN clauses but omits the "single-source" # part of the Join grammar: # # http://www.sqlite.org/syntaxdiagrams.html#join-source # # This visitor is used in SelectManager#join_sql and is for backwards # compatibility with Arel V1.0 module JoinSql private def visit_Arel_Nodes_SelectCore o o.source.right.map { |j| visit j }.join ' ' end end end end arel-4.0.0/lib/arel/visitors/postgresql.rb0000644000004100000410000000062312161114331020563 0ustar www-datawww-datamodule Arel module Visitors class PostgreSQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Matches o "#{visit o.left} ILIKE #{visit o.right}" end def visit_Arel_Nodes_DoesNotMatch o "#{visit o.left} NOT ILIKE #{visit o.right}" end def visit_Arel_Nodes_DistinctOn o "DISTINCT ON ( #{visit o.expr} )" end end end end arel-4.0.0/lib/arel/visitors.rb0000644000004100000410000000253212161114331016361 0ustar www-datawww-datarequire 'arel/visitors/visitor' require 'arel/visitors/depth_first' require 'arel/visitors/to_sql' require 'arel/visitors/sqlite' require 'arel/visitors/postgresql' require 'arel/visitors/mysql' require 'arel/visitors/mssql' require 'arel/visitors/oracle' require 'arel/visitors/join_sql' require 'arel/visitors/where_sql' require 'arel/visitors/order_clauses' require 'arel/visitors/dot' require 'arel/visitors/ibm_db' require 'arel/visitors/informix' module Arel module Visitors VISITORS = { 'postgresql' => Arel::Visitors::PostgreSQL, 'mysql' => Arel::Visitors::MySQL, 'mysql2' => Arel::Visitors::MySQL, 'mssql' => Arel::Visitors::MSSQL, 'sqlserver' => Arel::Visitors::MSSQL, 'oracle_enhanced' => Arel::Visitors::Oracle, 'sqlite' => Arel::Visitors::SQLite, 'sqlite3' => Arel::Visitors::SQLite, 'ibm_db' => Arel::Visitors::IBM_DB, 'informix' => Arel::Visitors::Informix, } ENGINE_VISITORS = Hash.new do |hash, engine| pool = engine.connection_pool adapter = pool.spec.config[:adapter] hash[engine] = (VISITORS[adapter] || Visitors::ToSql).new(engine) end def self.visitor_for engine ENGINE_VISITORS[engine] end class << self; alias :for :visitor_for; end end end arel-4.0.0/lib/arel/window_predications.rb0000644000004100000410000000016612161114331020553 0ustar www-datawww-datamodule Arel module WindowPredications def over(expr = nil) Nodes::Over.new(self, expr) end end endarel-4.0.0/lib/arel/alias_predication.rb0000644000004100000410000000017712161114331020154 0ustar www-datawww-datamodule Arel module AliasPredication def as other Nodes::As.new self, Nodes::SqlLiteral.new(other) end end endarel-4.0.0/lib/arel/attributes.rb0000644000004100000410000000114212161114331016661 0ustar www-datawww-datarequire 'arel/attributes/attribute' module Arel module Attributes ### # Factory method to wrap a raw database +column+ to an Arel Attribute. def self.for column case column.type when :string, :text, :binary then String when :integer then Integer when :float then Float when :decimal then Decimal when :date, :datetime, :timestamp, :time then Time when :boolean then Boolean else Undefined end end end end arel-4.0.0/lib/arel/tree_manager.rb0000644000004100000410000000106112161114331017124 0ustar www-datawww-datamodule Arel class TreeManager include Arel::FactoryMethods attr_reader :ast, :engine def initialize engine @engine = engine @ctx = nil end def to_dot Visitors::Dot.new.accept @ast end def visitor engine.connection.visitor end def to_sql visitor.accept @ast end def initialize_copy other super @ast = @ast.clone end def where expr if Arel::TreeManager === expr expr = expr.ast end @ctx.wheres << expr self end end end arel-4.0.0/lib/arel/order_predications.rb0000644000004100000410000000023612161114331020355 0ustar www-datawww-datamodule Arel module OrderPredications def asc Nodes::Ascending.new self end def desc Nodes::Descending.new self end end end arel-4.0.0/lib/arel/attributes/0000755000004100000410000000000012161114331016336 5ustar www-datawww-dataarel-4.0.0/lib/arel/attributes/attribute.rb0000644000004100000410000000124512161114331020670 0ustar www-datawww-datamodule Arel module Attributes class Attribute < Struct.new :relation, :name include Arel::Expressions include Arel::Predications include Arel::AliasPredication include Arel::OrderPredications include Arel::Math ### # Create a node for lowering this attribute def lower relation.lower self end end class String < Attribute; end class Time < Attribute; end class Boolean < Attribute; end class Decimal < Attribute; end class Float < Attribute; end class Integer < Attribute; end class Undefined < Attribute; end end Attribute = Attributes::Attribute end arel-4.0.0/lib/arel/deprecated.rb0000644000004100000410000000011612161114331016573 0ustar www-datawww-datamodule Arel InnerJoin = Nodes::InnerJoin OuterJoin = Nodes::OuterJoin end arel-4.0.0/lib/arel/update_manager.rb0000644000004100000410000000162512161114331017455 0ustar www-datawww-datamodule Arel class UpdateManager < Arel::TreeManager def initialize engine super @ast = Nodes::UpdateStatement.new @ctx = @ast end def take limit @ast.limit = Nodes::Limit.new(limit) if limit self end def key= key @ast.key = key end def key @ast.key end def order *expr @ast.orders = expr self end ### # UPDATE +table+ def table table @ast.relation = table self end def wheres= exprs @ast.wheres = exprs end def where expr @ast.wheres << expr self end def set values if String === values @ast.values = [values] else @ast.values = values.map { |column,value| Nodes::Assignment.new( Nodes::UnqualifiedColumn.new(column), value ) } end self end end end arel-4.0.0/lib/arel/sql/0000755000004100000410000000000012161114331014747 5ustar www-datawww-dataarel-4.0.0/lib/arel/sql/engine.rb0000644000004100000410000000024712161114331016544 0ustar www-datawww-datamodule Arel module Sql class Engine def self.new thing #warn "#{caller.first} -- Engine will be removed" thing end end end end arel-4.0.0/lib/arel/select_manager.rb0000644000004100000410000001660012161114331017451 0ustar www-datawww-datamodule Arel class SelectManager < Arel::TreeManager include Arel::Crud def initialize engine, table = nil super(engine) @ast = Nodes::SelectStatement.new @ctx = @ast.cores.last from table end def initialize_copy other super @ctx = @ast.cores.last end def limit @ast.limit && @ast.limit.expr end alias :taken :limit def constraints @ctx.wheres end def offset @ast.offset && @ast.offset.expr end def skip amount if amount @ast.offset = Nodes::Offset.new(amount) else @ast.offset = nil end self end alias :offset= :skip ### # Produces an Arel::Nodes::Exists node def exists Arel::Nodes::Exists.new @ast end def as other create_table_alias grouping(@ast), Nodes::SqlLiteral.new(other) end def where_clauses if $VERBOSE warn "(#{caller.first}) where_clauses is deprecated and will be removed in arel 4.0.0 with no replacement" end to_sql = Visitors::ToSql.new @engine.connection @ctx.wheres.map { |c| to_sql.accept c } end def lock locking = Arel.sql('FOR UPDATE') case locking when true locking = Arel.sql('FOR UPDATE') when Arel::Nodes::SqlLiteral when String locking = Arel.sql locking end @ast.lock = Nodes::Lock.new(locking) self end def locked @ast.lock end def on *exprs @ctx.source.right.last.right = Nodes::On.new(collapse(exprs)) self end def group *columns columns.each do |column| # FIXME: backwards compat column = Nodes::SqlLiteral.new(column) if String === column column = Nodes::SqlLiteral.new(column.to_s) if Symbol === column @ctx.groups.push Nodes::Group.new column end self end def from table table = Nodes::SqlLiteral.new(table) if String === table # FIXME: this is a hack to support # test_with_two_tables_in_from_without_getting_double_quoted # from the AR tests. case table when Nodes::Join @ctx.source.right << table else @ctx.source.left = table end self end def froms @ast.cores.map { |x| x.from }.compact end def join relation, klass = Nodes::InnerJoin return self unless relation case relation when String, Nodes::SqlLiteral raise if relation.blank? klass = Nodes::StringJoin end @ctx.source.right << create_join(relation, nil, klass) self end def having *exprs @ctx.having = Nodes::Having.new(collapse(exprs, @ctx.having)) self end def window name window = Nodes::NamedWindow.new(name) @ctx.windows.push window window end def project *projections # FIXME: converting these to SQLLiterals is probably not good, but # rails tests require it. @ctx.projections.concat projections.map { |x| [Symbol, String].include?(x.class) ? SqlLiteral.new(x.to_s) : x } self end def projections @ctx.projections end def projections= projections @ctx.projections = projections end def distinct(value = true) if value @ctx.set_quantifier = Arel::Nodes::Distinct.new else @ctx.set_quantifier = nil end end def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @ast.orders.concat expr.map { |x| String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x } self end def orders @ast.orders end def wheres warn "#{caller[0]}: SelectManager#wheres is deprecated and will be removed in Arel 4.0.0 with no replacement" Compatibility::Wheres.new @engine.connection, @ctx.wheres end def where_sql return if @ctx.wheres.empty? viz = Visitors::WhereSql.new @engine.connection Nodes::SqlLiteral.new viz.accept @ctx end def union operation, other = nil if other node_class = Nodes.const_get("Union#{operation.to_s.capitalize}") else other = operation node_class = Nodes::Union end node_class.new self.ast, other.ast end def intersect other Nodes::Intersect.new ast, other.ast end def except other Nodes::Except.new ast, other.ast end alias :minus :except def with *subqueries if subqueries.first.is_a? Symbol node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}") else node_class = Nodes::With end @ast.with = node_class.new(subqueries.flatten) self end def take limit if limit @ast.limit = Nodes::Limit.new(limit) @ctx.top = Nodes::Top.new(limit) else @ast.limit = nil @ctx.top = nil end self end alias limit= take def join_sql return nil if @ctx.source.right.empty? sql = visitor.dup.extend(Visitors::JoinSql).accept @ctx Nodes::SqlLiteral.new sql end def order_clauses visitor = Visitors::OrderClauses.new(@engine.connection) visitor.accept(@ast).map { |x| Nodes::SqlLiteral.new x } end def join_sources @ctx.source.right end def source @ctx.source end def joins manager if $VERBOSE warn "joins is deprecated and will be removed in 4.0.0" warn "please remove your call to joins from #{caller.first}" end manager.join_sql end class Row < Struct.new(:data) # :nodoc: def id data['id'] end def method_missing(name, *args) name = name.to_s return data[name] if data.key?(name) super end end def to_a # :nodoc: warn "to_a is deprecated. Please remove it from #{caller[0]}" # FIXME: I think `select` should be made public... @engine.connection.send(:select, to_sql, 'AREL').map { |x| Row.new(x) } end # FIXME: this method should go away def insert values if $VERBOSE warn <<-eowarn insert (#{caller.first}) is deprecated and will be removed in Arel 4.0.0. Please switch to `compile_insert` eowarn end im = compile_insert(values) table = @ctx.froms primary_key = table.primary_key primary_key_name = primary_key.name if primary_key # FIXME: in AR tests values sometimes were Array and not Hash therefore is_a?(Hash) check is added primary_key_value = primary_key && values.is_a?(Hash) && values[primary_key] im.into table # Oracle adapter needs primary key name to generate RETURNING ... INTO ... clause # for tables which assign primary key value using trigger. # RETURNING ... INTO ... clause will be added only if primary_key_value is nil # therefore it is necessary to pass primary key value as well @engine.connection.insert im.to_sql, 'AREL', primary_key_name, primary_key_value end private def collapse exprs, existing = nil exprs = exprs.unshift(existing.expr) if existing exprs = exprs.compact.map { |expr| if String === expr # FIXME: Don't do this automatically Arel.sql(expr) else expr end } if exprs.length == 1 exprs.first else create_and exprs end end end end arel-4.0.0/lib/arel/predications.rb0000644000004100000410000001015712161114331017165 0ustar www-datawww-datamodule Arel module Predications def not_eq other Nodes::NotEqual.new self, other end def not_eq_any others grouping_any :not_eq, others end def not_eq_all others grouping_all :not_eq, others end def eq other Nodes::Equality.new self, other end def eq_any others grouping_any :eq, others end def eq_all others grouping_all :eq, others end def in other case other when Arel::SelectManager Arel::Nodes::In.new(self, other.ast) when Range if other.begin == -Float::INFINITY && other.end == Float::INFINITY Nodes::NotIn.new self, [] elsif other.end == Float::INFINITY Nodes::GreaterThanOrEqual.new(self, other.begin) elsif other.begin == -Float::INFINITY && other.exclude_end? Nodes::LessThan.new(self, other.end) elsif other.begin == -Float::INFINITY Nodes::LessThanOrEqual.new(self, other.end) elsif other.exclude_end? left = Nodes::GreaterThanOrEqual.new(self, other.begin) right = Nodes::LessThan.new(self, other.end) Nodes::And.new [left, right] else Nodes::Between.new(self, Nodes::And.new([other.begin, other.end])) end else Nodes::In.new self, other end end def in_any others grouping_any :in, others end def in_all others grouping_all :in, others end def not_in other case other when Arel::SelectManager Arel::Nodes::NotIn.new(self, other.ast) when Range if other.begin == -Float::INFINITY && other.end == Float::INFINITY Nodes::In.new self, [] elsif other.end == Float::INFINITY Nodes::LessThan.new(self, other.begin) elsif other.begin == -Float::INFINITY && other.exclude_end? Nodes::GreaterThanOrEqual.new(self, other.end) elsif other.begin == -Float::INFINITY Nodes::GreaterThan.new(self, other.end) elsif other.exclude_end? left = Nodes::LessThan.new(self, other.begin) right = Nodes::GreaterThanOrEqual.new(self, other.end) Nodes::Or.new left, right else left = Nodes::LessThan.new(self, other.begin) right = Nodes::GreaterThan.new(self, other.end) Nodes::Or.new left, right end else Nodes::NotIn.new self, other end end def not_in_any others grouping_any :not_in, others end def not_in_all others grouping_all :not_in, others end def matches other Nodes::Matches.new self, other end def matches_any others grouping_any :matches, others end def matches_all others grouping_all :matches, others end def does_not_match other Nodes::DoesNotMatch.new self, other end def does_not_match_any others grouping_any :does_not_match, others end def does_not_match_all others grouping_all :does_not_match, others end def gteq right Nodes::GreaterThanOrEqual.new self, right end def gteq_any others grouping_any :gteq, others end def gteq_all others grouping_all :gteq, others end def gt right Nodes::GreaterThan.new self, right end def gt_any others grouping_any :gt, others end def gt_all others grouping_all :gt, others end def lt right Nodes::LessThan.new self, right end def lt_any others grouping_any :lt, others end def lt_all others grouping_all :lt, others end def lteq right Nodes::LessThanOrEqual.new self, right end def lteq_any others grouping_any :lteq, others end def lteq_all others grouping_all :lteq, others end private def grouping_any method_id, others nodes = others.map {|expr| send(method_id, expr)} Nodes::Grouping.new nodes.inject { |memo,node| Nodes::Or.new(memo, node) } end def grouping_all method_id, others Nodes::Grouping.new Nodes::And.new(others.map {|expr| send(method_id, expr)}) end end end arel-4.0.0/lib/arel/expression.rb0000644000004100000410000000011612161114331016672 0ustar www-datawww-datamodule Arel module Expression include Arel::OrderPredications end end arel-4.0.0/lib/arel/sql_literal.rb0000644000004100000410000000007512161114331017012 0ustar www-datawww-datamodule Arel class SqlLiteral < Nodes::SqlLiteral end end arel-4.0.0/lib/arel.rb0000644000004100000410000000154512161114331014502 0ustar www-datawww-datarequire 'arel/crud' require 'arel/factory_methods' require 'arel/expressions' require 'arel/predications' require 'arel/window_predications' require 'arel/math' require 'arel/alias_predication' require 'arel/order_predications' require 'arel/table' require 'arel/attributes' require 'arel/compatibility/wheres' #### these are deprecated require 'arel/expression' #### require 'arel/visitors' require 'arel/tree_manager' require 'arel/insert_manager' require 'arel/select_manager' require 'arel/update_manager' require 'arel/delete_manager' require 'arel/nodes' #### these are deprecated require 'arel/deprecated' require 'arel/sql/engine' require 'arel/sql_literal' #### module Arel VERSION = '4.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql end def self.star sql '*' end ## Convenience Alias Node = Arel::Nodes::Node end